Docker Compose入门

Docker Compose入门

简介

一般一个宿主机中会生成多个容器,容器与容器之间需要协调工作,有时多个容器之间也需要进行环境的隔离,而Docker Compose就是用来定义和运行多个容器的工具。可以通过一个yaml文件来配置应用程序的服务,并通过命令来管理所有服务的生命周期。

安装步骤

一般可以在Compose repository release page on GitHub获取到最新版的Docker Compse。

下载

执行以下命令:

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

如果需要其他版本的Docker Compse,只需要把命令中的1.29.2替换成需要的版本即可。

如果curl安装有问题,可以参照Alternative Install Options 进行安装。

赋予执行权限

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

检查是否安装成功

1
2
> docker-compose --version
docker-compose version 1.29.2, build 5becea4c

如何使用

基本配置

在docker compose下,存在服务的概念,一个compose配置可以由多个服务来组成,参考如下yaml配置:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
version: "3.9"
services:
db_mysql:
image: mysql
restart: always
container_name: my-mysql
ports:
- 10001:3306
environment:
MYSQL_ROOT_PASSWORD: new_password_xxx
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
volumes:
- /usr/local/docker/mysql/data/:/var/lib/mysql
- /usr/local/docker/mysql/conf.d:/etc/mysql/conf.d

redis:
image: redis
hostname: redis-server
restart: always
container_name: my-redis
ports:
- 10002:6379
command: redis-server /etc/redis/redis.conf --appendonly yes
volumes:
- /usr/local/docker/redis/conf/redis.conf:/etc/redis/redis.conf

nginx:
image: nginx
restart: always
container_name: my-nginx
ports:
- 80:80
volumes:
- /usr/local/docker/nginx/nginx.conf:/etc/nginx/nginx.conf

redis-commander:
container_name: redis-commander
hostname: redis-commander
image: rediscommander/redis-commander:latest
restart: always
environment:
- REDIS_HOSTS=local:redis-server:6379
ports:
- 11002:8081

存在一个services节点,该节点下定义了三个服务。每个服务会对应到一个镜像,当执行docker-compose up之后,会根据每个服务对应的镜像,生成对应的容器。服务的名称可以自行定义,无强制要求。

在yaml所在目录下执行

1
2
3
4
5
> docker-compose up -d
Creating network "docker-compose_default" with the default driver
Creating my-mysql ... done
Creating my-nginx ... done
Creating my-redis ... done

up为创建并启动所有容器,-d表示守护态运行。这里不指定配置文件名称,则默认当前目录下的名为docker-compose.yml的文件。不指定项目名称,则默认该配置文件所在的目录名称作为项目名称。

可以看到配置文件所定义的所有服务均正常启动。

1
2
3
4
5
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ea6c7d60903d redis "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 0.0.0.0:10002->6379/tcp, :::10002->6379/tcp my-redis
49062f5891e7 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp my-nginx
d63a6ed103f5 mysql "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 33060/tcp, 0.0.0.0:10001->3306/tcp, :::10001->3306/tcp my-mysql

常用命令

对于docker-compose有如下选项。

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
Commands:
build Build or rebuild services
config Validate and view the Compose file
create Create services
down Stop and remove resources
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 version information and quit

讲一些比较常用的。

up命令,用于创建并启动compose项目。

然后就是startstop等,仅进行启动和停止服务。

如果是执行down命令,在停止所有服务容器的同时,也会删除所有容器以及网络。

如果改变了一个服务的Dockerfile或者构建目录的内容,可以使用build命令对其进行重建。

ps的用法都差不多,查看所有正在运行的容器。

每个命令具体用法,还是要参见--help

容器与容器间的访问

一般创建容器

当docker创建一个容器时,会将它纳入一个网络。如果是单独创建容器,则会纳入默认的bridge网络中(默认为bridge模式),如:

新建一个tomcat容器:

1
2
> docker pull tomcat
> docker run --name my-tomcat --rm -p 8080:8080 -d tomcat

通过dockers network命令查看

1
2
3
4
5
6
> docker network ls
NETWORK ID NAME DRIVER SCOPE
3d18fe44fe65 bridge bridge local
de7157fb3e93 docker-compose_default bridge local
da3cd2189967 host host local
098d7dd513d5 none null local

可以看到,有一个name为brideg的网络,查看详细信息:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
> docker network inspect bridge
[
{
"Name": "bridge",
"Id": "3d18fe44fe65f8d4f370adc558ce41a92897ce58288fa2f16aa2787dcebd9e0c",
"Created": "2021-07-11T17:04:49.64883344+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"e42b6c1b108d756cc266cb29d0f6d779c396d62fbc5eef556ad42356ec275b9e": {
"Name": "my-tomcat",
"EndpointID": "00e0c410554cb08d4c4c65861d844fc98297f32ca9be628087c934f44bccb82b",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]

其中Containers有刚刚创建的my-tomcat容器。

docker-compose创建的网络

在使用docker-compose创建一个项目后,会将该项目中所有的服务(services)都纳入到同一个网络当中,默认的网络名称为项目名加上_default,如上面的docker-compose_default网络。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
> docker network inspect docker-compose_default
[
{
"Name": "docker-compose_default",
"Id": "de7157fb3e937908299c17cd3d21380a5dca2960a93bcb9da0ed392f5a4d74d7",
"Created": "2021-08-01T10:46:49.281728229+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"49062f5891e7d12eccbefb19875bcc0bd16b8e79906abb4952bb0420c1d09d72": {
"Name": "my-nginx",
"EndpointID": "c3e9773c7cb20222762f37784a24d35912e48edaf332408f61c6be19033382c2",
"MacAddress": "02:42:ac:13:00:04",
"IPv4Address": "172.19.0.4/16",
"IPv6Address": ""
},
"d63a6ed103f525148402f57919648e2e7caadd43d51a36597b058a7ecfedf8e4": {
"Name": "my-mysql",
"EndpointID": "391283e8835fa8107c6eb95ef946ffabaff8daa9ac5f6325274224f40925cead",
"MacAddress": "02:42:ac:13:00:03",
"IPv4Address": "172.19.0.3/16",
"IPv6Address": ""
},
"ea6c7d60903ded82d4c26d5fa47cdcdb005eba94ff5ff825e65e3815e44aab88": {
"Name": "my-redis",
"EndpointID": "1dc8f641e6599117fbc9ba605a0940ed1f71b630646db2553670d64fd361d853",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.docker.compose.network": "default",
"com.docker.compose.project": "docker-compose",
"com.docker.compose.version": "1.29.2"
}
}
]

其中包含了我们创建的三个服务容器。

容器与容器间需要进行网络通信,使用的是CONTAINER_IP:CONTAINER_PORT,而不是映射到宿主机的ip和端口。

举个例子,新加入一个服务到上面的docker-compose.yml中。

1
2
3
4
5
6
7
8
9
10
11
12
version: 3.9
services:
# 省略之前的内容
redis-commander:
container_name: redis-commander
hostname: redis-commander
image: rediscommander/redis-commander:latest
restart: always
environment:
- REDIS_HOSTS=local:redis:6379
ports:
- 11002:8081

environment需要配置redis容器的地址,这里使用local:redis:6379,其中的redis为compose中定义的服务名,通过服务名,docker可以自己获取该服务的当前ip。端口使用的是6379,而非映射的10002。

保存yml后,重新执行docker-compose up -d,会更新有变化的容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
> docker-compose up -d
Pulling redis-commander (rediscommander/redis-commander:latest)...
latest: Pulling from rediscommander/redis-commander
339de151aab4: Pull complete
f732fa32fc61: Pull complete
ef60bb667d5a: Pull complete
4f50fa5032a4: Pull complete
Digest: sha256:19cd0c49f418779fa2822a0496c5e6516d0c792effc39ed20089e6268477e40a
Status: Downloaded newer image for rediscommander/redis-commander:latest
my-redis is up-to-date
my-nginx is up-to-date
Creating redis-commander ...
Creating redis-commander ... done

访问11002端口,可以看到redis-commander已成功部署,并正常连接到了我们所配置的redis服务。

image-20210801154319824