Docker学习笔记第五篇-Compose篇

这篇我们学习下DockerCompose

部署一个wordpress

首先准备好两个镜像:

1
2
3
4
[vagrant@docker-host ~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql latest 2dd01afbe8df 5 days ago 485MB
wordpress latest 9451d745d1dd 13 days ago 408MB

我们需要搭建的wordpress由两部分组成,一个是web服务,一个是对应的数据服务。

先创建一个MySQL的容器

image-20181030163853073

创建MySQL容器的时候指定数据的root账户密码和数据库名字。

这里我们不用把3306端口映射出来的原因是我们并不想外面访问,在同一个Docker主机上的容器在同一个网络上是可以直接访问该容器的端口的。

创建wordpress的容器

1
2
[vagrant@docker-host ~]$  docker run -d -e WORDPRESS_DB_HOST=mysql:3306 --link mysql -p 8080:80 wordpress
89dd8a8cb34d27c2eb9563838ffe176e51a54ccafa06dd1079529a2a7b02afd7
  • -e WORDPRESS_DB_PASSWORD=... (defaults to the value of the MYSQL_ROOT_PASSWORDenvironment variable from the linked mysql container)

这样直接访问本地8080端口即可。

这样我们使用了两个容器启动了一个wordpress

对于一个服务需要多个容器的话我们需要分别管理各个容器,有些麻烦。

我们可以将这些容器当成一个组,可以统一管理(启动,删除等),这就是Docker Compose

Docker Compo到底是什么?
  • Docker Compo是一个命令行工具,可以批处理容器。
  • 这个工具可以通过一个yml文件定义多容器的docker应用。
  • 通过一个命令就可以根据yml文件的定义去创建或者管理这多个容器

官方文档:https://docs.docker.com/compose/compose-file/#reference-and-guidelines

这个关键的yml文件有一个默认的名字docker-compose.yml,我们是可以修改这个名字的。

不同版本的Compose的功能是稍微不同的:对于version 3来说是支持多机的,version 2是不支持多机的。

现在一般都是使用version 3,我们看下一个师范的yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
version: "3"
services:

redis:
image: redis:alpine
ports:
- "6379"
networks:
- frontend
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure

db:
image: postgres:9.4
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
placement:
constraints: [node.role == manager]

networks:
frontend:
backend:

volumes:
db-data:

Composeyml文件中有三个主要的组成:Services,Networks,Volumes

service

一个service代表一个container,这个container可以从dockerhubimage来创建,或者从本地的Dockerfile build出来的image来创建。

Service的启动类似docker run,我们可以给其指定networkvolume,所以可以给service指定networkVolume的引用。

我们看个栗子:

1
2
3
4
5
6
7
services:
db:
image: postgres:9.4
volumes:
- "db-data:/var/lib/postgresql/data"
networks:
- back-tier

上面的yaml文件功能和下面的一样:

1
docker run -d --network back-tier -v db-data:/var/lib/postgresql/data postgres:9.4

我们还可以直接指定Dockerfile文件,build出对应的镜像。

1
2
3
4
5
6
7
8
service:
worker:
build: ./worker
links:
- db
- redis
networks:
- back-tier
Volumes

我们看到上面的yaml文件中有使用volumes:

1
2
volumes:
- "db-data:/var/lib/postgresql/data"

这么引用是因为我们需要在和services同级的地方定义一下这个volumes

1
2
volumes:
db-data:

上面相当于创建了一个volumes

1
docker volume create db-data
Networks

我们看到上面的yaml文件中有使用networks:

1
2
networks:
- back-tier

这么引用是因为我们需要在和services同级的地方定义一下这个networks

1
2
3
networks:
back-tier:
driver: bridge

上面的相当于使用bridge当驱动创建了一个名为back-tier的网络。

1
docker network create -d bridge back-tier

我们看下如何将第一个小节部署的wordpress服务通过Docker Composeyaml抒写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
version: '3'	# 表示使用版本

services:

wordpress: # 容器名字
image: wordpress # 使用的镜像
ports: # 端口映射
- 8080:80
environment: # 设置环境变量 相当于命令行下的 -e 参数
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD: root
networks: # 指定网络
- my-bridge

mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress
volumes: # 指定使用容器
- mysql-data:/var/lib/mysql
networks:
- my-bridge

volumes: # 创建容器
mysql-data:

networks: # 创建网络
my-bridge: # 指定使用驱动
driver: bridge
Docker Compose的安装和基本使用
安装

我们看下Linux环境下如何安装

官方文档:https://docs.docker.com/compose/install/#install-compose

直接执行下面命令安装:

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

赋予可执行权限

1
sudo chmod +x /usr/local/bin/docker-compose

验证版本

1
2
[root@hongshaorou ~]# docker-compose --version
docker-compose version 1.22.0, build f46880fe
使用

我们看看如何使用

1
2
3
4
5
6
7
➜  wordpress ls
docker-compose.yml
➜ wordpress docker-compose -f docker-compose.yml up
Creating network "wordpress_my-bridge" with driver "bridge"
Creating volume "wordpress_mysql-data" with default driver
Creating wordpress_mysql_1 ... done
Creating wordpress_wordpress_1 ... done

当我们使用docker-compose up的时候会默认执行当前目录下名为docker-compose.yml的文件,我们同样可以使用-f参数指定文件。

1
2
3
➜  wordpress docker-compose -f docker-compose.yml up -d
Creating wordpress_wordpress_1 ... done
Creating wordpress_mysql_1 ... done

我们看下命令有哪些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Commands:
build Build or rebuild services
bundle Generate a Docker bundle from the Compose file
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show the Docker-Compose version information

使用ps列出创建的容器。

上面说错了一点,services名字并不是容器的名字。

1
2
3
4
5
➜  wordpress docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------------------
wordpress_mysql_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
wordpress_wordpress_1 docker-entrypoint.sh apach ... Up 0.0.0.0:8080->80/tcp

使用stop停止,使用start开启,使用down停止并删除

1
2
3
4
5
6
7
➜  wordpress docker-compose stop
Stopping wordpress_mysql_1 ... done

➜ wordpress docker-compose down
Removing wordpress_mysql_1 ... done
Removing wordpress_wordpress_1 ... done
Removing network wordpress_my-bridge

使用images可以查看创建的容器及其使用镜像

1
2
3
4
5
➜  wordpress docker-compose images
Container Repository Tag Image Id Size
-------------------------------------------------------------------
wordpress_mysql_1 mysql latest 2dd01afbe8df 463 MB
wordpress_wordpress_1 wordpress latest 9451d745d1dd 389 MB

使用exec进入到容器中

1
2
➜  wordpress docker-compose exec mysql bash
root@292a8a89eba0:/#

上面我们使用的yaml文件是直接从远程拉取镜像,下面我们看一个Flask程序,镜像是通过Dockerfile创建而来的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
➜  flask-redis ls
Dockerfile app.py docker-compose.yml
➜ flask-redis cat docker-compose.yml
version: "3"

services:

redis:
image: redis

web:
build:
context: . # 上下文环境当前目录 指定 Dockerfile 的位置
dockerfile: Dockerfile
ports:
- 8080:5000
environment:
REDIS_HOST: redis

直接使用compose进行创建容器

1
2
3
➜  flask-redis docker-compose up -d
Creating network "flask-redis_default" with the default driver
Building web

运行完成后 查看浏览器

image-20181031170351728

这样我们就使用compose通过Dockerfile创建了一个完成的容器应用。

水平扩展和负载均衡

上面我们已经成功运行起来了web服务,但是是单一的服务,当存在高并发的时候可用性较差。

image-20181031172404411

这个小节,我们将完成上面的一个具有负载均衡的多服务的一个配置。

实现的主要技术点是使用scale,将容器扩展到指定数目。

1
2
--scale SERVICE=NUM        Scale SERVICE to NUM instances. Overrides the
`scale` setting in the Compose file if present.

现在我们使用上节的yaml文件做实验,不过需要修改调端口映射,防止报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
version: "3"

services:

redis:
image: redis

web:
build:
context: .
dockerfile: Dockerfile
environment:
REDIS_HOST: redis

我们先运行起整个服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
➜  flask-redis docker-compose up -d
Creating network "flask-redis_default" with the default driver
Creating flask-redis_redis_1 ... done
Creating flask-redis_web_1 ... done

➜ flask-redis docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------
flask-redis_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
flask-redis_web_1 python app.py Up 5000/tcp

# 将 web 服务扩展至 3 个
➜ flask-redis docker-compose up --scale web=3 -d
flask-redis_redis_1 is up-to-date
Starting flask-redis_web_1 ... done
Creating flask-redis_web_2 ... done
Creating flask-redis_web_3 ... done

# 我们可以看到 web 服务已经扩展到 3 个
➜ flask-redis docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------
flask-redis_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
flask-redis_web_1 python app.py Up 5000/tcp
flask-redis_web_2 python app.py Up 5000/tcp
flask-redis_web_3 python app.py Up 5000/tcp

上面三个web服务监听的事容器的5000端口,并没有端口映射,这三个web服务都会访问redis服务。

这时候虽然服务多了起来,但是还是需要一个负载均衡将访问均分到每个web服务。

现在我们根据老师提供的文件,增加上负载均衡。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
➜  lb-scale ls
Dockerfile app.py docker-compose.yml
➜ lb-scale cat docker-compose.yml
version: "3"

services:

redis:
image: redis

web:
build:
context: .
dockerfile: Dockerfile
environment:
REDIS_HOST: redis

lb:
image: dockercloud/haproxy
links:
- web
ports:
- 8080:80 # 将监听的 80 转发到 8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock

首先我们创建服务:

1
2
3
4
5
6
7
8
9
10
11
➜  lb-scale ls
Dockerfile app.py docker-compose.yml
➜ lb-scale docker-compose up -d
Creating network "lb-scale_default" with the default driver

➜ lb-scale docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------------------------
lb-scale_lb_1 /sbin/tini -- dockercloud- ... Up 1936/tcp, 443/tcp, 0.0.0.0:8080->80/tcp
lb-scale_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
lb-scale_web_1 python app.py Up 80/tcp

看看有哪些容器

1
2
3
4
5
➜  lb-scale docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ebd82d6299df dockercloud/haproxy "/sbin/tini -- docke…" About a minute ago Up About a minute 443/tcp, 1936/tcp, 0.0.0.0:8080->80/tcp lb-scale_lb_1
9853af9f950d redis "docker-entrypoint.s…" About a minute ago Up About a minute 6379/tcp lb-scale_redis_1
69117a34ca80 lb-scale_web "python app.py" About a minute ago Up About a minute 80/tcp lb-scale_web_1

访问我们创建的服务

1
2
➜  lb-scale curl 127.0.0.1:8080
Hello Container World! I have been seen 1 times and my hostname is 69117a34ca80.

最后的69117a34ca80是容容器的ID。

我们将wbe服务扩展为三个然后再访问服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
➜  lb-scale docker-compose up --scale web=3 -d
Starting lb-scale_web_1 ...
Starting lb-scale_web_1 ... done
Creating lb-scale_web_2 ... done
Creating lb-scale_web_3 ... done
lb-scale_lb_1 is up-to-date
➜ lb-scale curl 127.0.0.1:8080
Hello Container World! I have been seen 2 times and my hostname is 69117a34ca80.
➜ lb-scale curl 127.0.0.1:8080
Hello Container World! I have been seen 3 times and my hostname is b5be3d9d4418.
➜ lb-scale curl 127.0.0.1:8080
Hello Container World! I have been seen 4 times and my hostname is 86bbf0c65c3d.
➜ lb-scale curl 127.0.0.1:8080
Hello Container World! I have been seen 5 times and my hostname is 69117a34ca80.

通过最后打印的容器ID,我们可以看到通过负载均衡轮询分配。

scale不仅可以往大的方向扩展,还可以往小的方向收缩

知识就是财富
如果您觉得文章对您有帮助, 欢迎请我喝杯水!