通过前几章节,我们知道:
而实际项目中,特别是微服务化之后,运维需要面对的不单单是一个镜像一个容器,而是几十乃至上千。如果通过手工敲命令去创建一个个容器,不科学也太慢。如果遇到机器更新换代或者重启,又得重新敲一遍,这样下去我想迟早脑袋头发都要掉光。
还好docker提前想到了这点,为我们准备了相应的工具:
还有一个很时尚的工具 Kubernetes ,它是Google根据自身十几年经验打造的。
Compose 是由Python 编写,定义和运行多个 Docker 容器的工具。通过一个 docker-compose.yml 模板文件(YAML 格式)来定义应用服务,简单的命令批量创建和启动定义的所有服务。
重要概念:
一个项目可以由多个服务(容器)关联而成,Compose 面向项目进行管理。
特性:
使用不同的项目名称可以在一个主机构建不同组应用环境。比如开发主机上的不同项目。
默认项目名称为yml文件所在目录名称,通过使用-p projectname 可以自定义项目名称。创建的镜像和容器名称前缀会带上项目名称。
保存已经创建容器里头挂载的数据。运行 docker-compose up 的时候,如果监测到有运行的容器,它会自动把就容器挂载的数据复制到新的容器。
Compose会缓存创建容器的配置,重启service时只会重建有更改的容器。
yml模板文件支持可变参数,使用参数可以创建不同的应用。
db: image: "postgres:${POSTGRES_VERSION}"
YML 模板文件常用配置:
version:compose文件格式版本号,最新版为3。
Compose file format | Docker Engine release |
---|---|
3.8 | 19.03.0+ |
3.7 | 18.06.0+ |
3.6 | 18.02.0+ |
3.5 | 17.12.0+ |
3.4 | 17.09.0+ |
3.3 | 17.06.0+ |
3.2 | 17.04.0+ |
3.1 | 1.13.1+ |
3.0 | 1.13.0+ |
2.4 | 17.12.0+ |
2.3 | 17.06.0+ |
2.2 | 1.13.0+ |
2.1 | 1.12.0+ |
2.0 | 1.10.0+ |
1.0 | 1.9.1.+ |
services:服务父节点。
通过镜像创建容器的docker-compose.yml文件
version: "3" services: #容器唯一标识 webapp: #镜像名称 image: examples/web ports: - "80:80" volumes: - "/data"
通过DockerFile编译创建容器的docker-compose.yml文件
version: '3' services: #容器唯一标识 webapp: build: #DockerFile文件地址 context: ./dir #DockerFile文件名称 dockerfile: Dockerfile-alternate
安装:
$ sudo curl -L https://github.com/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose $ sudo chmod +x /usr/local/bin/docker-compose
常见命令:
D:/docker/03-compose>docker-compose ps Name Command State Ports --------------------------------------------------------------------- 03-compose_nbaspnetcore_1 dotnet aspnetcoreapp.dll Exit 0 03-compose_nbginx_1 /bin/sh -c /bin/bash Exit 0
D:/docker/03-compose>docker-compose images Container Repository Tag Image Id Size -------------------------------------------------------------------------------------- 03-compose_nbaspnetcore_1 03-compose_nbaspnetcore latest 73ae1ad12839 211.9 MB 03-compose_nbginx_1 03-compose_nbginx latest 61ed0bb949f6 403.8 MB
D:/docker/03-compose>docker-compose ps Name Command State Ports ----------------------------------------------------------------------------------------------------------- 03-compose_nbaspnetcore_1 dotnet aspnetcoreapp.dll Up 0.0.0.0:6067->443/tcp, 0.0.0.0:6066->80/tcp 03-compose_nbginx_1 /bin/sh -c /bin/bash Exit 0 D:/docker/03-compose>docker-compose rm Going to remove 03-compose_nbginx_1 Are you sure? [yN] y Removing 03-compose_nbginx_1 ... done D:/docker/03-compose>docker-compose ps Name Command State Ports ---------------------------------------------------------------------------------------------------------- 03-compose_nbaspnetcore_1 dotnet aspnetcoreapp.dll Up 0.0.0.0:6067->443/tcp, 0.0.0.0:6066->80/tcp
实例
下面用 Python 来建立一个能够记录页面访问次数的 web 网站。
新建composetest文件夹,在该目录中编写 app.py 文件。
import time import redis from flask import Flask app = Flask(__name__) cache = redis.Redis(host='redis', port=6379) def get_hit_count(): retries = 5 while True: try: return cache.incr('hits') except redis.exceptions.ConnectionError as exc: if retries == 0: raise exc retries -= 1 time.sleep(0.5) @app.route('/') def hello(): count = get_hit_count() return 'Hello World! 该页面已被访问 {} 次。/n'.format(count)
在文件夹中,添加 Dockerfile 文件
FROM python:3.7-alpine WORKDIR /code ENV FLASK_APP app.py ENV FLASK_RUN_HOST 0.0.0.0 RUN apk add --no-cache gcc musl-dev linux-headers RUN pip install redis flask COPY . . CMD ["flask", "run"]
在文件夹外部创建 docker-compose.yml 文件
version: '3' services: webtest: build: ./composetest ports: - 5000:5000 redis: image: redis:alpine
运行Compose项目。(项目名称为plana)
D:/docker/03-compose>docker-compose -p plana up Creating network "plana_default" with the default driver Building webtest Step 1/8 : FROM python:3.7-alpine ---> 16f919b9ecd5 Step 2/8 : WORKDIR /code ---> Using cache ---> 3cd944ab4513 Step 3/8 : ENV FLASK_APP app.py ---> Using cache ---> 2aa9917f4c9f Step 4/8 : ENV FLASK_RUN_HOST 0.0.0.0 ---> Using cache ---> db1028a91223 Step 5/8 : RUN apk add --no-cache gcc musl-dev linux-headers ---> Using cache ---> 13a0ed97a7dd Step 6/8 : RUN pip install redis flask ---> Using cache ---> 1807263196e2 Step 7/8 : COPY . . ---> Using cache ---> 553b6c68eace Step 8/8 : CMD ["flask", "run"] ---> Using cache ---> ad92e1924ad5 Successfully built ad92e1924ad5 Successfully tagged plana_webtest:latest WARNING: Image for service webtest was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`. Creating plana_redis_1 ... done Creating plana_webtest_1 ... done Attaching to plana_webtest_1, plana_redis_1 redis_1 | 1:C 29 Apr 2020 12:59:36.795 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo redis_1 | 1:C 29 Apr 2020 12:59:36.795 # Redis version=5.0.9, bits=64, commit=00000000, modified=0, pid=1, just started redis_1 | 1:C 29 Apr 2020 12:59:36.795 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf redis_1 | 1:M 29 Apr 2020 12:59:36.800 * Running mode=standalone, port=6379. redis_1 | 1:M 29 Apr 2020 12:59:36.800 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. redis_1 | 1:M 29 Apr 2020 12:59:36.800 # Server initialized redis_1 | 1:M 29 Apr 2020 12:59:36.801 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. redis_1 | 1:M 29 Apr 2020 12:59:36.802 * Ready to accept connections webtest_1 | * Serving Flask app "app.py" webtest_1 | * Environment: production webtest_1 | WARNING: This is a development server. Do not use it in a production deployment. webtest_1 | Use a production WSGI server instead. webtest_1 | * Debug mode: off webtest_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
执行结果。(需要指定项目名称)
D:/docker/03-compose>docker-compose ps Name Command State Ports ------------------------------ D:/docker/03-compose>docker-compose images Container Repository Tag Image Id Size ---------------------------------------------- D:/docker/03-compose>docker-compose -p plana images Container Repository Tag Image Id Size ------------------------------------------------------------------ plana_redis_1 redis alpine 3661c84ee9d0 29.8 MB plana_webtest_1 plana_webtest latest ad92e1924ad5 219.7 MB D:/docker/03-compose>docker-compose -p plana ps Name Command State Ports --------------------------------------------------------------------------------- plana_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp plana_webtest_1 flask run Up 0.0.0.0:5000->5000/tcp
Swarm 是使用 SwarmKit 构建的 Docker 引擎内置(原生)的集群管理和编排工具。
Docker 1.12开始 Swarm mode 已经内嵌入 Docker 引擎,成为了 docker 子命令 docker swarm
。
Swarm mode 内置 kv 存储功能,提供了众多的新特性,使得 Docker 原生的 Swarm 集群具备与 Mesos、Kubernetes 竞争的实力。比如:
常见概念
节点
节点为作用在Swarm集群中的一个实例化Docker引擎。虽然可以在一台物理主机上部署多个节点,但是生产环境中都是跨物理主机进行。
节点可以加入已经存在的swarm集群或者将自己初始化为一个swarm集群。
分为:管理(manager)节点,工作(worker)节点。
服务(Service)与任务(Task)
使用实例
使用 play-with-docker 实验。
初始化管理节点
$ docker swarm init Error response from daemon: could not choose an IP address to advertise since this system has multiple addresses on different interfaces (192.168.0.48 on eth0 and 172.18.0.53 on eth1) - specify one with --advertise-addr
因为有多个网络地址需要指定
$ docker swarm init --advertise-addr 192.168.0.48 Swarm initialized: current node (uas5ayulwp28ldrcr3bscmitr) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-17khjeqkfmjswynhda1i0dfqw4hy5io2006xktyvav272ccfie-6xomx3u1mvm7pacj0ymheyu6e 192.168.0.48:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
查看节点列表
$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION uas5ayulwp28ldrcr3bscmitr * node1 Ready Active Leader 19.03.4
加入工作节点
$ docker swarm join --token SWMTKN-1-17khjeqkfmjswynhda1i0dfqw4hy5io2006xktyvav272ccfie-6xomx3u1mvm7pacj0ymheyu6e 192.168.0.48:2377 This node joined a swarm as a worker.
在两个主机执行以上命令之后,去管理节点查看节点列表
$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION uas5ayulwp28ldrcr3bscmitr * node1 Ready Active Leader 19.03.4 2rum5pm81t76tjv91rld1n8vu node3 Ready Active 19.03.4 u4tbyt95nhy7l6vj3z013r8wz node5 Ready Active 19.03.4
服务部署
(命令都是在管理节点执行。)
新建服务
在集群中创建nginx服务。
$ docker service create --replicas 3 -p 80:80 --name nginx nginx:latest stieixvmvfipi4w6qh49t9es0 overall progress: 3 out of 3 tasks 1/3: running 2/3: running 3/3: running verify: Service converged
查看服务
查看服务列表:
$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS stieixvmvfip nginx replicated 3/3 nginx:latest *:80->80/tcp
查看服务详细:
$ docker service ps nginx ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS xgc5u5m5gl9p nginx.1 nginx:latest node3 Running Running 2 minutes ago y76pttbz9pkh nginx.2 nginx:latest node5 Running Running 2 minutes ago oti754af3izt nginx.3 nginx:latest node1 Running Running 2 minutes ago
浏览器中输入管理节点或者工作节点IP地址都可以查看nginx界面。
管理节点:
工作节点1:
工作节点2:
服务伸缩
$ docker service scale nginx=2 nginx scaled to 2 overall progress: 2 out of 2 tasks 1/2: running 2/2: running verify: Service converged查看服务详情:
$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS stieixvmvfip nginx replicated 2/2 nginx:latest *:80->80/tcp
$ docker service scale nginx=3 nginx scaled to 3 overall progress: 3 out of 3 tasks 1/3: running 2/3: running 3/3: running verify: Service converged
删除服务
$ docker service rm nginx nginx
查看服务:
$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS
通过compose文件部署服务
docker service create 一次只能部署一个服务,使用 docker-compose.yml 可以一次启动多个关联的服务
version: "3" services: nginx: image: nginx:latest ports: - 80:80 deploy: mode: replicated replicas: 3
$ docker stack deploy -c docker-compose.yml nginx Creating network nginx_default Creating service nginx_nginx
$ docker stack ls NAME SERVICES ORCHESTRATOR nginx 1 Swarm
$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS 92n4xd254vu1 nginx_nginx replicated 3/3 nginx:latest *:80->80/tcp
$ docker service ps nginx_nginx ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS p6d3xibx9swx nginx_nginx.1 nginx:latest node1 Running Running 2 minutes ago v0taw0rnr9v3 nginx_nginx.2 nginx:latest node3 Running Running 2 minutes ago 2z3sbkdo16oi nginx_nginx.3 nginx:latest node5 Running Running 2 minutes ago
$ docker stack down nginx Removing service nginx_nginx Removing network nginx_default