官网https://docs.docker.com/compose/

6.1 业务背景

6.2 Docker传统方式实现

6.2.1 写Python代码&build image

(1)创建文件夹

  1. mkdir -p /tmp/composetest
  2. cd /tmp/composetest

(2)创建app.py文件,写业务内容

  1. import time
  2. import redis
  3. from flask import Flask
  4. app = Flask(__name__)
  5. cache = redis.Redis(host='redis', port=6379)
  6. def get_hit_count():
  7. retries = 5
  8. while True:
  9. try:
  10. return cache.incr('hits')
  11. except redis.exceptions.ConnectionError as exc:
  12. if retries == 0:
  13. raise exc
  14. retries -= 1
  15. time.sleep(0.5)
  16. @app.route('/')
  17. def hello():
  18. count = get_hit_count()
  19. return 'Hello World! I have been seen {} times.\n'.format(count)

(3)新建requirements.txt文件

  1. flask
  2. redis

(4)编写Dockerfile

  1. FROM python:3.7-alpine
  2. WORKDIR /code
  3. ENV FLASK_APP app.py
  4. ENV FLASK_RUN_HOST 0.0.0.0
  5. RUN apk add --no-cache gcc musl-dev linux-headers
  6. COPY requirements.txt requirements.txt
  7. RUN pip install -r requirements.txt
  8. COPY . .
  9. CMD ["flask", "run"]

(5)根据Dockerfile生成image

  1. docker build -t python-app-image .

(6)查看images:docker images

  1. python-app-image latest 7e1d81f366b7 3 minutes ago 213MB

6.2.2 获取Redis的image

  1. docker pull redis:alpine

6.2.3 创建两个container

(1)创建网络

  1. docker network ls
  2. docker network create --subnet=172.20.0.0/24 app-net

(1)创建python程序的container,并指定网段和端口

  1. docker run -d --name web -p 5000:5000 --network app-net python-app-image

(2)创建redis的container,并指定网段

  1. docker run -d --name redis --network app-net redis:alpine

6.2.4 访问测试

ip[centos]:5000

6.3 简介和安装

6.3.1 简介

官网https://docs.docker.com/compose/

  1. Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your applications services. Then, with a single command, you create and start all the services from your configuration.

6.3.2 安装

Linux环境中需要单独安装

官网https://docs.docker.com/compose/install/

  1. sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  1. sudo chmod +x /usr/local/bin/docker-compose

6.4 docker compose实现

referencehttps://docs.docker.com/compose/gettingstarted/

6.4.1 同样的前期准备

新建目录,比如composetest

进入目录,编写app.py代码

创建requirements.txt文件

编写Dockerfile

6.4.2 编写docker-compose.yaml文件

默认名称,当然也可以指定,docker-compose.yaml

  1. version: '3'
  2. services:
  3. web:
  4. build: .
  5. ports:
  6. - "5000:5000"
  7. networks:
  8. - app-net
  9. redis:
  10. image: "redis:alpine"
  11. networks:
  12. - app-net
  13. networks:
  14. app-net:
  15. driver: bridge

(1)通过docker compose创建容器

  1. docker-compose up -d

(2)访问测试

6.5 详解docker-compose.yml文件

(1)version: ‘3’

  1. 表示docker-compose的版本

(2)services

  1. 一个service表示一个container

(3)networks

  1. 相当于docker network create app-net

(4)volumes

  1. 相当于-v v1:/var/lib/mysql

(5)image

  1. 表示使用哪个镜像,本地build则用build,远端则用image

(6)ports

  1. 相当于-p 8080:8080

(7)environment

  1. 相当于-e

6.6 docker-compose常见操作

(1)查看版本

  1. docker-compose version

(2)根据yml创建service

  1. docker-compose up
  2. 指定yamldocker-compose up -f xxx.yaml
  3. 后台运行:docker-compose up

(3)查看启动成功的service

  1. docker-compose ps
  2. 也可以使用docker ps

(4)查看images

  1. docker-compose images

(5)停止/启动service

  1. docker-compose stop/start

(6)删除service[同时会删除掉network和volume]

  1. docker-compose down

(7)进入到某个service

  1. docker-compose exec redis sh

6.7 scale扩缩容

(1)修改docker-compose.yaml文件,主要是把web的ports去掉,不然会报错

  1. version: '3'
  2. services:
  3. web:
  4. build: .
  5. networks:
  6. - app-net
  7. redis:
  8. image: "redis:alpine"
  9. networks:
  10. - app-net
  11. networks:
  12. app-net:
  13. driver: bridge

(2)创建service

  1. docker-compose up -d

(3)若要对python容器进行扩缩容

  1. docker-compose up --scale web=5 -d
  2. docker-compose ps
  3. docker-compose logs web

07 Docker Swarm

官网https://docs.docker.com/swarm/

7.1 Install Swarm

7.1.1 环境准备

(1)根据Vagrantfile创建3台centos机器

[大家可以根据自己实际的情况准备3台centos机器,不一定要使用vagrant+virtualbox]

新建swarm-docker-centos7文件夹,创建Vagrantfile

  1. boxes = [
  2. {
  3. :name => "manager-node",
  4. :eth1 => "192.168.0.11",
  5. :mem => "1024",
  6. :cpu => "1"
  7. },
  8. {
  9. :name => "worker01-node",
  10. :eth1 => "192.168.0.12",
  11. :mem => "1024",
  12. :cpu => "1"
  13. },
  14. {
  15. :name => "worker02-node",
  16. :eth1 => "192.168.0.13",
  17. :mem => "1024",
  18. :cpu => "1"
  19. }
  20. ]
  21. Vagrant.configure(2) do |config|
  22. config.vm.box = "centos/7"
  23. boxes.each do |opts|
  24. config.vm.define opts[:name] do |config|
  25. config.vm.hostname = opts[:name]
  26. config.vm.provider "vmware_fusion" do |v|
  27. v.vmx["memsize"] = opts[:mem]
  28. v.vmx["numvcpus"] = opts[:cpu]
  29. end
  30. config.vm.provider "virtualbox" do |v|
  31. v.customize ["modifyvm", :id, "--memory", opts[:mem]]
  32. v.customize ["modifyvm", :id, "--cpus", opts[:cpu]]
  33. v.customize ["modifyvm", :id, "--name", opts[:name]]
  34. end
  35. config.vm.network :public_network, ip: opts[:eth1]
  36. end
  37. end
  38. end

(2)进入到对应的centos里面,使得root账户能够登陆,从而使用XShell登陆

  1. vagrant ssh manager-node/worker01-node/worker02-node
  2. sudo -i
  3. vi /etc/ssh/sshd_config
  4. 修改PasswordAuthentication yes
  5. passwd 修改密码
  6. systemctl restart sshd

(3)在win上ping一下各个主机,看是否能ping通

  1. ping 192.168.0.11/12/13

(4)在每台机器上安装docker engine

小技巧:要想让每个shell窗口一起执行同样的命令”查看—>撰写—>撰写窗口—>全部会话”

7.1.2 搭建Swarm集群

(1)进入manager

提示:manager node也可以作为worker node提供服务

  1. docker swarm init --advertise-addr=192.168.0.11

注意观察日志,拿到worker node加入manager node的信息

  1. docker swarm join --token SWMTKN-1-0a5ph4nehwdm9wzcmlbj2ckqqso38pkd238rprzwcoawabxtdq-arcpra6yzltedpafk3qyvv0y3 192.168.0.11:2377

(2)进入两个worker

  1. docker swarm join --token SWMTKN-1-0a5ph4nehwdm9wzcmlbj2ckqqso38pkd238rprzwcoawabxtdq-arcpra6yzltedpafk3qyvv0y3 192.168.0.11:2377

日志打印

  1. This node joined a swarm as a worker.

(3)进入到manager node查看集群状态

  1. docker node ls

(4)node类型的转换

可以将worker提升成manager,从而保证manager的高可用

  1. docker node promote worker01-node
  2. docker node promote worker02-node
  3. #降级可以用demote
  4. docker node demote worker01-node

7.1.3 在线的

http://labs.play-with-docker.com

7.2 Swarm基本操作

7.2.1 Service

(1)创建一个tomcat的service

  1. docker service create --name my-tomcat tomcat

(2)查看当前swarm的service

  1. docker service ls

(3)查看service的启动日志

  1. docker service logs my-tomcat

(4)查看service的详情

  1. docker service inspect my-tomcat

(5)查看my-tomcat运行在哪个node上

  1. docker service ps my-tomcat

日志

  1. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  2. u6o4mz4tj396 my-tomcat.1 tomcat:latest worker01-node Running Running 3 minutes ago

(6)水平扩展service

  1. docker service scale my-tomcat=3
  2. docker service ls
  3. docker service ps my-tomcat

日志:可以发现,其他node上都运行了一个my-tomcat的service

  1. [root@manager-node ~]# docker service ps my-tomcat
  2. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  3. u6o4mz4tj396 my-tomcat.1 tomcat:latest worker01-node Running Running 8 minutes ago
  4. v505wdu3fxqo my-tomcat.2 tomcat:latest manager-node Running Running 46 seconds ago
  5. wpbsilp62sc0 my-tomcat.3 tomcat:latest worker02-node Running Running 49 seconds ago

此时到worker01-node上:docker ps,可以发现container的name和service名称不一样,这点要知道

  1. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  2. bc4b9bb097b8 tomcat:latest "catalina.sh run" 10 minutes ago Up 10 minutes 8080/tcp my-tomcat.1.u6o4mz4tj3969a1p3mquagxok

(7)如果某个node上的my-tomcat挂掉了,这时候会自动扩展

  1. [worker01-node]
  2. docker rm -f containerid
  3. [manager-node]
  4. docker service ls
  5. docker service ps my-tomcat

(8)删除service

  1. docker service rm my-tomcat

7.2.2 多机通信overlay网络[3.7的延续]

业务场景:workpress+mysql实现个人博客搭建

https://hub.docker.com/_/wordpress?tab=description

7.2.2.1 传统手动方式实现

7.2.2.1.1 一台centos上,分别创建容器
  1. 01-创建mysql容器[创建完成等待一会,注意mysql的版本]
  2. docker run -d --name mysql -v v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=examplepass -e MYSQL_DATABASE=db_wordpress mysql:5.6
  3. 02-创建wordpress容器[将wordpress80端口映射到centos8080端口]
  4. docker run -d --name wordpress --link mysql -e WORDPRESS_DB_HOST=mysql:3306 -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=examplepass -e WORDPRESS_DB_NAME=db_wordpress -p 8080:80 wordpress
  5. 03-查看默认bridge的网络,可以发现两个容器都在其中
  6. docker network inspect bridge
  7. 04-访问测试
  8. win浏览器中输入:ip[centos]:8080,一直下一步

7.2.2.1.2 使用docker compose创建

docker-compose的方式还是在一台机器中,网络这块很清晰

  1. 01-创建wordpress-mysql文件夹
  2. mkdir -p /tmp/wordpress-mysql
  3. cd /tmp/wordpress-mysql
  4. 02-创建docker-compose.yml文件

文件内容

  1. version: '3.1'
  2. services:
  3. wordpress:
  4. image: wordpress
  5. restart: always
  6. ports:
  7. - 8080:80
  8. environment:
  9. WORDPRESS_DB_HOST: db
  10. WORDPRESS_DB_USER: exampleuser
  11. WORDPRESS_DB_PASSWORD: examplepass
  12. WORDPRESS_DB_NAME: exampledb
  13. volumes:
  14. - wordpress:/var/www/html
  15. db:
  16. image: mysql:5.7
  17. restart: always
  18. environment:
  19. MYSQL_DATABASE: exampledb
  20. MYSQL_USER: exampleuser
  21. MYSQL_PASSWORD: examplepass
  22. MYSQL_RANDOM_ROOT_PASSWORD: '1'
  23. volumes:
  24. - db:/var/lib/mysql
  25. volumes:
  26. wordpress:
  27. db:
  1. 03-根据docker-compose.yml文件创建service
  2. docker-compose up -d
  3. 04-访问测试
  4. win10浏览器ip[centos]:8080,一直下一步
  5. 05-值得关注的点是网络
  6. docker network ls
  7. docker network inspect wordpress-mysql_default

7.2.2.2 Swarm中实现

还是wordpress+mysql的案例,在docker swarm集群中怎么玩呢?

(1)创建一个overlay网络,用于docker swarm中多机通信

  1. manager-node
  2. docker network create -d overlay my-overlay-net
  3. docker network ls[此时worker node查看不到]

(2)创建mysql的service

  1. manager-node
  2. 01-创建service
  3. docker service create --name mysql --mount type=volume,source=v1,destination=/var/lib/mysql --env MYSQL_ROOT_PASSWORD=examplepass --env MYSQL_DATABASE=db_wordpress --network my-overlay-net mysql:5.6
  4. 02-查看service
  5. docker service ls
  6. docker service ps mysql

(3)创建wordpress的service

  1. 01-创建service [注意之所以下面可以通过mysql名字访问,也是因为有DNS解析]
  2. docker service create --name wordpress --env WORDPRESS_DB_USER=root --env WORDPRESS_DB_PASSWORD=examplepass --env WORDPRESS_DB_HOST=mysql:3306 --env WORDPRESS_DB_NAME=db_wordpress -p 8080:80 --network my-overlay-net wordpress
  3. 02-查看service
  4. docker service ls
  5. docker service ps mysql
  6. 03-此时mysqlwordpressservice运行在哪个node上,这时候就能看到my-overlay-net的网络

(4)测试

  1. win浏览器访问ip[manager/worker01/worker02]:8080都能访问成功

(5)查看my-overlay-net

  1. docker network inspect my-overlay-net

(6)为什么没有用etcd?docker swarm中有自己的分布式存储机制

7.3 Routing Mesh

7.3.1 Ingress

通过前面的案例我们发现,部署一个wordpress的service,映射到主机的8080端口,这时候通过swarm集群中的任意主机ip:8080都能成功访问,这是因为什么?

把问题简化:docker service create —name tomcat -p 8080:8080 —network my-overlay-net tomcat

(1)记得使用一个自定义的overlay类型的网络

  1. --network my-overlay-net

(2)查看service情况

  1. docker service ls
  2. docker service ps tomcat

(3)访问3台机器的ip:8080测试

  1. 发现都能够访问到tomcat的欢迎页

7.4.2 Internal

之前在实战wordpress+mysql的时候,发现wordpress中可以直接通过mysql名称访问

这样可以说明两点,第一是其中一定有dns解析,第二是两个service的ip是能够ping通的

思考:不妨再创建一个service,也同样使用上述tomcat的overlay网络,然后来实验

docker service create —name whoami -p 8000:8000 —network my-overlay-net -d jwilder/whoami

(1)查看whoami的情况

  1. docker service ps whoami

(2)在各自容器中互相ping一下彼此,也就是容器间的通信

  1. #tomcat容器中ping whoami
  2. docker exec -it 9d7d4c2b1b80 ping whoami
  3. 64 bytes from bogon (10.0.0.8): icmp_seq=1 ttl=64 time=0.050 ms
  4. 64 bytes from bogon (10.0.0.8): icmp_seq=2 ttl=64 time=0.080 ms
  5. #whoami容器中ping tomcat
  6. docker exec -it 5c4fe39e7f60 ping tomcat
  7. 64 bytes from bogon (10.0.0.18): icmp_seq=1 ttl=64 time=0.050 ms
  8. 64 bytes from bogon (10.0.0.18): icmp_seq=2 ttl=64 time=0.080 ms

(3)将whoami进行扩容

  1. docker service scale whoami=3
  2. docker service ps whoami #manager,worker01,worker02

(4)此时再ping whoami service,并且访问whoami服务

  1. #ping
  2. docker exec -it 9d7d4c2b1b80 ping whoami
  3. 64 bytes from bogon (10.0.0.8): icmp_seq=1 ttl=64 time=0.055 ms
  4. 64 bytes from bogon (10.0.0.8): icmp_seq=2 ttl=64 time=0.084 ms
  5. #访问
  6. docker exec -it 9d7d4c2b1b80 curl whoami:8000 [多访问几次]
  7. I'm 09f4158c81ae
  8. I'm aebc574dc990
  9. I'm 7755bc7da921

小结:通过上述的实验可以发现什么?whoami服务对其他服务暴露的ip是不变的,但是通过whoami名称访问8000端口,确实访问到的是不同的service,就说明访问其实是像下面这张图。

也就是说whoami service对其他服务提供了一个统一的VIP入口,别的服务访问时会做负载均衡。

7.5 Stack

docker stack deploy:https://docs.docker.com/engine/reference/commandline/stack_deploy/

compose-file:https://docs.docker.com/compose/compose-file/

有没有发现上述部署service很麻烦?要是能够类似于docker-compose.yml文件那种方式一起管理该多少?这就要涉及到docker swarm中的Stack,我们直接通过前面的wordpress+mysql案例看看怎么使用咯。

(1)新建service.yml文件

  1. version: '3'
  2. services:
  3. wordpress:
  4. image: wordpress
  5. ports:
  6. - 8080:80
  7. environment:
  8. WORDPRESS_DB_HOST: db
  9. WORDPRESS_DB_USER: exampleuser
  10. WORDPRESS_DB_PASSWORD: examplepass
  11. WORDPRESS_DB_NAME: exampledb
  12. networks:
  13. - ol-net
  14. volumes:
  15. - wordpress:/var/www/html
  16. deploy:
  17. mode: replicated
  18. replicas: 3
  19. restart_policy:
  20. condition: on-failure
  21. delay: 5s
  22. max_attempts: 3
  23. update_config:
  24. parallelism: 1
  25. delay: 10s
  26. db:
  27. image: mysql:5.7
  28. environment:
  29. MYSQL_DATABASE: exampledb
  30. MYSQL_USER: exampleuser
  31. MYSQL_PASSWORD: examplepass
  32. MYSQL_RANDOM_ROOT_PASSWORD: '1'
  33. volumes:
  34. - db:/var/lib/mysql
  35. networks:
  36. - ol-net
  37. deploy:
  38. mode: global
  39. placement:
  40. constraints:
  41. - node.role == manager
  42. volumes:
  43. wordpress:
  44. db:
  45. networks:
  46. ol-net:
  47. driver: overlay

(2)根据service.yml创建service

  1. docker statck deploy -c service.yml my-service

(3)常见操作

  1. 01-查看stack具体信息
  2. docker stack ls
  3. NAME SERVICES ORCHESTRATOR
  4. my-service 2 Swarm
  5. 02-查看具体的service
  6. docker stack services my-service
  7. ID NAME MODE REPLICAS IMAGE PORTS
  8. icraimlesu61 my-service_db global 1/1 mysql:5.7
  9. iud2g140za5c my-service_wordpress replicated 3/3 wordpress:latest *:8080->80/tcp
  10. 03-查看某个service
  11. docker service inspect my-service-db
  12. "Endpoint": {
  13. "Spec": {
  14. "Mode": "vip"
  15. },
  16. "VirtualIPs": [
  17. {
  18. "NetworkID": "kz1reu3yxxpwp1lvnrraw0uq6",
  19. "Addr": "10.0.1.5/24"
  20. }
  21. ]
  22. }

(4)访问测试

win浏览器ip[manager,worker01,worker02]:8080