在单独container中部署使用

首先,kafka依赖zookeeper,即使只是单机使用,也得按集群的方式来配置……

所以,先下载两个官方images:

  1. docker pull confluentinc/cp-zookeeper
  2. docker pull confluentinc/cp-kafka

然后创建一个compose:

  1. services:
  2. zookeeper:
  3. image: confluentinc/cp-zookeeper
  4. container_name: zookeeper
  5. mem_limit: 1024M
  6. environment:
  7. ZOOKEEPER_CLIENT_PORT: 2181
  8. volumes:
  9. - ./zookeeper/data:/data
  10. - ./zookeeper/datalog:/datalog
  11. ports: #端口映射
  12. - "2181:2181"
  13. kafka:
  14. image: confluentinc/cp-kafka
  15. container_name: kafka
  16. mem_limit: 1024M
  17. depends_on:
  18. - zookeeper
  19. environment:
  20. KAFKA_BROKER_NO: 1
  21. KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1 # 修改
  22. KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://127.0.0.1:9092 # 修改
  23. KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
  24. KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
  25. KAFKA_HEAP_OPTS: "-Xmx512M -Xms16M"
  26. volumes:
  27. - ./kafka/logs:/kafka/logs
  28. ports:
  29. - "9092:9092"
  30. ## 镜像:开源的web管理kafka集群的界面
  31. kafka-manager:
  32. image: sheepkiller/kafka-manager
  33. environment:
  34. ZK_HOSTS: 127.0.0.1
  35. ports:
  36. - "21105:9000"

注意绑定相关端口,不然本地Spring程序无法访问,只能进入容器内访问!(如果直接在服务器上测试的,为安全起见暂不绑定相关端口)。

启动compose:

  1. docker-compose -f docker-compose.yml up -d

Screen Shot 2021-11-19 at 1.01.29 AM.png

现在打开两个新的终端窗口,分别用以下命令登录container:

  1. docker exec -it kafka /bin/bash

在其中一个窗口里创建topic并运行producer:

  1. kafka-topics --zookeeper zookeeper:2181 --create --replication-factor 1 --partitions 1 --topic kafkatest
  2. kafka-console-producer --broker-list localhost:9092 --topic kafkatest

新版本的kafka,已经不需要依赖zookeeper来创建topic,新版的kafka创建topic指令为下:

  1. kafka-topics --create --bootstrap-server kafka:9092 --replication-factor 1 --partitions 1 --topic kafkatest
  2. kafka-console-producer --broker-list localhost:9092 --topic kafkatest

注意,这里的kafka是kafka服务器对应的IP映射的主机名,改成该kafka服务器对应的IP也可。

可以在docker中使用如下命令查看容器信息:

  1. docker inspect confluentinc/cp-kafka的容器ID

在Docker环境下的kafka部署 - 图2

在另一个窗口里运行consumer:

  1. kafka-console-consumer --bootstrap-server localhost:9092 --topic kafkatest --from-beginning

新版的kafka开启消费者控制台指令为下:

  1. kafka-console-consumer --bootstrap-server localhost:9092 --topic kafkatest --from-beginning

现在,在producer里输入任何内容,都会在consumer里收到。

查看kafka版本号

kafka没有提供version命令,不确定是否有方便的方法,但你可以进入kafka/libs文件夹。你应该看到像kafka_2.10-0.8.2-beta.jar这样的文件,其中2.10是Scala版本,0.8.2-beta是Kafka版本。
docker的话在/usr/share/java/kafka/

跨container的部署

上面的配置只能在单个container里使用,不实用。这是因为kafka advertised配置在localhost上。

需要跨container访问,就需要通过docker的网络访问,要修改这个配置:

  1. version: '2'
  2. services:
  3. zookeeper:
  4. image: confluentinc/cp-zookeeper
  5. container_name: zookeeper
  6. mem_limit: 1024M
  7. environment:
  8. ZOOKEEPER_CLIENT_PORT: 2181
  9. kafka:
  10. image: confluentinc/cp-kafka
  11. container_name: kafka
  12. mem_limit: 1024M
  13. depends_on:
  14. - zookeeper
  15. environment:
  16. KAFKA_BROKER_NO: 1
  17. KAFKA_ADVERTISED_HOST_NAME: domain_name # 修改
  18. KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://domain_name:9092 # 修改
  19. KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
  20. KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
  21. KAFKA_HEAP_OPTS: "-Xmx512M -Xms16M"

改完重启docker-compose,另外,因为zookeeper重启后,topic不会被持久保存,所以重启后需要重新创建topic。

然后启动两个新的container模拟网络访问:

  1. docker run -it --rm --link kafka:domain_name --network kafka_default --name consumer confluentinc/cp-kafka /bin/bash
  2. docker run -it --rm --link kafka:domain_name --network kafka_default --name producer confluentinc/cp-kafka /bin/bash

注意,需要指定一下docker网络为kafka_default,这是官方image使用的默认网络。

然后分别在consumer和producer两个container里测试:

  1. kafka-console-consumer --bootstrap-server domain_name:9092 --topic kafkatest --from-beginning
  2. kafka-console-producer --broker-list domain_name:9092 --topic kafkatest

效果与单container一样。

部署kafka集群的docker-compose.yml

  1. version: '3'
  2. services:
  3. zoo1:
  4. image: zookeeper
  5. restart: always
  6. container_name: zoo1
  7. ports:
  8. - "2181:2181"
  9. environment:
  10. ZOO_MY_ID: 1
  11. ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
  12. volumes:
  13. - ./zoo1/data:/data
  14. - ./zoo1/datalog:/datalog
  15. zoo2:
  16. image: zookeeper
  17. restart: always
  18. container_name: zoo2
  19. ports:
  20. - "2182:2181"
  21. environment:
  22. ZOO_MY_ID: 2
  23. ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
  24. volumes:
  25. - ./zoo2/data:/data
  26. - ./zoo2/datalog:/datalog
  27. zoo3:
  28. image: zookeeper
  29. restart: always
  30. container_name: zoo3
  31. ports:
  32. - "2183:2181"
  33. environment:
  34. ZOO_MY_ID: 3
  35. ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
  36. volumes:
  37. - ./zoo3/data:/data
  38. - ./zoo3/datalog:/datalog
  39. kafka1:
  40. image: wurstmeister/kafka
  41. ports:
  42. - "20540:9092"
  43. environment:
  44. KAFKA_ADVERTISED_HOST_NAME: 192.168.1.73
  45. KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://192.168.1.73:20540
  46. KAFKA_ZOOKEEPER_CONNECT: zoo1:2181,zoo2:2181,zoo3:2181
  47. KAFKA_ADVERTISED_PORT: 9092
  48. KAFKA_BROKER_ID: 1
  49. KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
  50. KAFKA_LOG_DIRS: /kafka/logs
  51. volumes:
  52. - ./kafka1/logs:/kafka/logs
  53. depends_on:
  54. - zoo1
  55. - zoo2
  56. - zoo3
  57. container_name: kafka1
  58. kafka2:
  59. image: wurstmeister/kafka
  60. ports:
  61. - "9093:9092"
  62. environment:
  63. KAFKA_ADVERTISED_HOST_NAME: 192.168.1.73
  64. KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://192.168.1.73:9093
  65. KAFKA_ZOOKEEPER_CONNECT: zoo1:2181,zoo2:2181,zoo3:2181
  66. KAFKA_ADVERTISED_PORT: 9093
  67. KAFKA_BROKER_ID: 2
  68. KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
  69. KAFKA_LOG_DIRS: /kafka/logs
  70. volumes:
  71. - ./kafka2/logs:/kafka/logs
  72. depends_on:
  73. - zoo1
  74. - zoo2
  75. - zoo3
  76. container_name: kafka2
  77. kafka3:
  78. image: wurstmeister/kafka
  79. ports:
  80. - "9094:9092"
  81. environment:
  82. KAFKA_ADVERTISED_HOST_NAME: 192.168.1.73
  83. KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://192.168.1.73:9094
  84. KAFKA_ZOOKEEPER_CONNECT: zoo1:2181,zoo2:2181,zoo3:2181
  85. KAFKA_ADVERTISED_PORT: 9094
  86. KAFKA_BROKER_ID: 3
  87. KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
  88. KAFKA_LOG_DIRS: /kafka/logs
  89. volumes:
  90. - ./kafka3/logs:/kafka/logs
  91. depends_on:
  92. - zoo1
  93. - zoo2
  94. - zoo3
  95. container_name: kafka3
  96. ## 镜像:开源的web管理kafka集群的界面
  97. kafka-manager:
  98. image: sheepkiller/kafka-manager
  99. environment:
  100. ZK_HOSTS: 192.168.1.73
  101. ports:
  102. - "21105:9000"

从Docker网络之外访问的部署

如果需要从docker网络之外访问,就需要把端口映射到宿主机了。

同样需要修改配置,增加网络映射等:

  1. version: '2'
  2. services:
  3. zookeeper:
  4. image: confluentinc/cp-zookeeper
  5. container_name: zookeeper
  6. mem_limit: 1024M
  7. environment:
  8. ZOOKEEPER_CLIENT_PORT: 2181
  9. kafka:
  10. image: confluentinc/cp-kafka
  11. container_name: kafka
  12. mem_limit: 1024M
  13. depends_on:
  14. - zookeeper
  15. ports: # 增加
  16. - 9092:9092 # 增加
  17. environment:
  18. KAFKA_BROKER_NO: 1
  19. KAFKA_ADVERTISED_HOST_NAME: domain_name
  20. KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://domain_name:9092
  21. KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
  22. KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
  23. KAFKA_HEAP_OPTS: "-Xmx512M -Xms16M"

然后启动两个新的container模拟外部网络访问:

  1. docker run -it --rm --add-host=domain_name:172.17.0.1 --name consumer confluentinc/cp-kafka /bin/bash
  2. docker run -it --rm --add-host=domain_name:172.17.0.1 --name producer confluentinc/cp-kafka /bin/bash

其中172.17.0.1为docker宿主机在默认docker网络(注意不是kafka_default)里的IP,具体可以通过以下命令查看:

  1. ip route

然后分别在consumer和producer两个container里测试:

  1. kafka-console-consumer --bootstrap-server domain_name:9092 --topic kafkatest --from-beginning
  2. kafka-console-producer --broker-list domain_name:9092 --topic kafkatest

这里有一个坑需要注意的是:

如果宿主机上有防火墙,需要增加一条规则,允许docker网络访问宿主机的端口,否则会连接失败。比如:

  1. # 取得行号
  2. iptables -L INPUT --line-num
  3. # xx为最后一行DROP的行号,插到它前面
  4. iptables -I INPUT xx -p tcp -m tcp -s 172.17.0.0/16 --dport 9092 -j ACCEPT

效果与前两个例子相同。

docker-compose启动

我有一个 docker-compose.yml 文件,其中包含多个容器:redis,postgres,mysql,worker

在的工作过程中,我经常需要重新启动它才能更新。有没有什么好的方法来重新启动一个容器(例如 worker )而不重新启动其他容器?

解决方案这很简单:使用命令:

docker-compose restart worker

您可以设置等待停止的时间,然后再杀死容器(以秒为单位)

docker-compose restart -t 30 worker

另外还有一种情况就是,本地修改了代码,需要重新打包发布,但是又不想全部docker-compose停止再启动,那么就可以单独修改其中一个。

  1. 首先通过 docker ps 查询已启动的容器(docker ps -a 查询所有容器,包括未启动的)
    命令 docker container ls -a 也一样。
  2. 将要更新的容器停止docker-compose stop worker (docker-compose stop 是停止yaml包含的所有容器)
  3. 将第二步已停止的容器删除 docker container rm c2cbf59d4e3c (c2cbf59d4e3c是worker的容器id)
  4. 查询所有的镜像 docker images
  5. 备份镜像,防止意外出错可恢复。docker save worker -o /home/bak/worker-bak.tar
  6. 删除镜像 docker rmi worker
  7. 将打包好的更新的jar文件按照docker-compose的描述地址放好,再根据文件编译新的镜像 docker build . -f Dockerfile-Worker -t worker
  8. 启动docker-compose up -d worker
  9. 重启docker-compose restart worker

Dockerfile-Worker

  1. FROM jdk1.8
  2. WORKDIR /app
  3. COPY ./target/worker.jar app.jar
  4. CMD java -Xmx512m -Duser.timezone=GMT+8 -jar app.jar

docker-compose.yml

  1. version: '3'
  2. services:
  3. redis:
  4. image: redis
  5. container_name: docker_redis
  6. volumes:
  7. - ./datadir:/data
  8. - ./conf/redis.conf:/usr/local/etc/redis/redis.conf
  9. - ./logs:/logs
  10. ports:
  11. - "20520:6379"
  12. mysql-db:
  13. container_name: mysql-docker # 指定容器的名称
  14. image: mysql:5.7.16 # 指定镜像和版本
  15. restart: always
  16. command: --default-authentication-plugin=mysql_native_password #这行代码解决无法访问的问题
  17. ports:
  18. - "3306:3306"
  19. environment:
  20. MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
  21. MYSQL_ROOT_HOST: ${MYSQL_ROOT_HOST}
  22. volumes:
  23. - "./mysql/data:/var/lib/mysql" # 挂载数据目录
  24. - "./mysql/config:/etc/mysql/conf.d" # 挂载配置文件目录
  25. register-center:
  26. image: register-center
  27. volumes:
  28. - /data/logs:/app/logs
  29. mem_limit: 600m
  30. extra_hosts:
  31. - 'node1.nifi-dev.com:192.168.1.10'
  32. - 'node2.nifi-dev.com:192.168.1.10'
  33. - 'node3.nifi-dev.com:192.168.1.10'
  34. environment:
  35. - CUR_ENV=sit
  36. ports:
  37. - "20741:8761"
  38. config-center:
  39. image: config-center
  40. volumes:
  41. - /data/logs:/app/logs
  42. - /data/skywalking/agent:/agent
  43. mem_limit: 2000m
  44. extra_hosts:
  45. - 'node1.nifi-dev.com:192.168.1.10'
  46. - 'node2.nifi-dev.com:192.168.1.10'
  47. - 'node3.nifi-dev.com:192.168.1.10'
  48. depends_on:
  49. - register-center
  50. environment:
  51. - EUREKA_SERVER_LIST=http://register-center:8761/eureka/
  52. command: /wait-for.sh register-center:8761/eureka/apps -- java -javaagent:/agent/skywalking-agent.jar -Dskywalking.agent.service_name=config-center -Dskywalking.collector.backend_service=192.168.1.147:20764 -Xmx256m -jar /app/app.jar --server.port=8760
  53. woeker:
  54. image: woeker
  55. volumes:
  56. - /data/logs:/app/logs
  57. mem_limit: 600m
  58. extra_hosts:
  59. - 'node1.nifi-dev.com:192.168.1.10'
  60. - 'node2.nifi-dev.com:192.168.1.10'
  61. - 'node3.nifi-dev.com:192.168.1.10'
  62. environment:
  63. - CUR_ENV=sit
  64. ports:
  65. - "20741:8761"

参考文档

How to Install Apache Kafka Using Docker — The Easy Way