docker-compose:单机环境下的容器编排工具

思考并回答以下问题:

docker-compose,是一个在单机环境里轻量级的容器编排工具。

如何使用docker-compose

GitHub上提供了多种形式的二进制可执行文件。

1
2
3
4
5
6
7
8
9
10
11
# intel x86_64
sudo curl -SL https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-x86_64 \
-o /usr/local/bin/docker-compose

# apple m1
sudo curl -SL https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-aarch64 \
-o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose version

接下来,我们就要编写YAML文件,来管理Docker容器了,先用第7讲里的私有镜像仓库作为示范吧。

docker-compose里管理容器的核心概念是“service”。注意,它与Kubernetes里的Service虽然名字很像,但却是完全不同的东西。docker-compose里的“service”就是一个容器化的应用程序,通常是一个后台服务,用YAML定义这些容器的参数和相互之间的关系。

如果硬要和Kubernetes对比的话,和“service”最像的API对象应该算是Pod里的container了,同样是管理容器运行,但docker-compose的“service”又融合了一些Service、Deployment的特性。

下面的这个就是私有镜像仓库Registry的YAML文件,关键字段就是“services”,对应的Docker命令我也列了出来:

1
docker run -d -p 5000:5000 registry

1
2
3
4
5
6
7
services:
registry:
image: registry
container_name: registry
restart: always
ports:
- 5000:5000

把它和Kubernetes对比一下,你会发现它和Pod定义非常像,“services”相当于Pod,而里面的“service”就相当于“spec.containers”:

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Pod
metadata:
name: ngx-pod
spec:
restartPolicy: Always
containers:
- image: nginx:alpine
name: ngx
ports:
- containerPort: 80

比如用image声明镜像,用ports声明端口,很容易理解,只是在用法上有些不一样,像端口映射用的就还是Docker的语法。

需要提醒的是,在docker-compose里,每个“service”都有一个自己的名字,它同时也是这个容器的唯一网络标识,有点类似Kubernetes里Service域名的作用。

好,现在我们就可以启动应用了,命令是docker-compose up -d,同时还要用-f参数来指定YAML文件,和kubectl apply差不多:

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

因为docker-compose在底层还是调用的Docker,所以它启动的容器用docker ps也能够看到:

不过,我们用docker-compose ps能够看到更多的信息:

1
docker-compose -f reg-compose.yml ps

下面我们把Nginx的镜像改个标签,上传到私有仓库里测试一下:

1
2
docker tag nginx:alpine 127.0.0.1:5000/nginx:v1
docker push 127.0.0.1:5000/nginx:v1

再用curl查看一下它的标签列表,就可以看到确实上传成功了:
1
curl 127.1:5000/v2/nginx/tags/list

想要停止应用,我们需要使用docker-compose down命令:

1
docker-compose -f reg-compose.yml down

通过这个小例子,我们就成功地把“命令式”的Docker操作,转换成了“声明式”的docker-compose操作,用法与Kubernetes十分接近,同时还没有Kubernetes那些昂贵的运行成本,在单机环境里可以说是最适合不过了。

使用docker-compose搭建WordPress网站

不过,私有镜像仓库Registry里只有一个容器,不能体现docker-compose容器编排的好处,我们再用它来搭建一次WordPress网站,深入感受一下。

架构图和第7讲还是一样的:

第一步还是定义数据库MariaDB,环境变量的写法与Kubernetes的ConfigMap有点类似,但使用的字段是environment,直接定义,不用再“绕一下”:

1
2
3
4
5
6
7
8
9
10
11
12
services:

mariadb:
image: mariadb:10
container_name: mariadb
restart: always

environment:
MARIADB_DATABASE: db
MARIADB_USER: wp
MARIADB_PASSWORD: 123
MARIADB_ROOT_PASSWORD: 123

我们可以再对比第7讲里启动MariaDB的Docker命令,可以发现docker-compose的YAML和命令行是非常像的,几乎可以直接照搬:
1
2
3
4
5
6
docker run -d --rm \
--env MARIADB_DATABASE=db \
--env MARIADB_USER=wp \
--env MARIADB_PASSWORD=123 \
--env MARIADB_ROOT_PASSWORD=123 \
mariadb:10

第二步是定义WordPress网站,它也使用environment来设置环境变量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
services:
...

wordpress:
image: wordpress:5
container_name: wordpress
restart: always

environment:
WORDPRESS_DB_HOST: mariadb #注意这里,数据库的网络标识
WORDPRESS_DB_USER: wp
WORDPRESS_DB_PASSWORD: 123
WORDPRESS_DB_NAME: db

depends_on:
- mariadb

不过,因为docker-compose会自动把MariaDB的名字用做网络标识,所以在连接数据库的时候(字段WORDPRESS_DB_HOST)就不需要手动指定IP地址了,直接用“service”的名字mariadb就行了。这是docker-compose比Docker命令要方便的一个地方,和Kubernetes的域名机制很像。

WordPress定义里还有一个值得注意的是字段depends_on,它用来设置容器的依赖关系,指定容器启动的先后顺序,这在编排由多个容器组成的应用的时候是一个非常便利的特性。

第三步就是定义Nginx反向代理了,不过很可惜,docker-compose里没有ConfigMap、Secret这样的概念,要加载配置还是必须用外部文件,无法集成进YAML。

Nginx的配置文件和第7讲里也差不多,同样的,在proxy_pass指令里不需要写IP地址了,直接用WordPress的名字就行:

1
2
3
4
5
6
7
8
9
10
server {
listen 80;
default_type text/html;

location / {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_pass http://wordpress; #注意这里,网站的网络标识
}
}

然后我们就可以在YAML里定义Nginx了,加载配置文件用的是volumes字段,和Kubernetes一样,但里面的语法却又是Docker的形式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
services:
...

nginx:
image: nginx:alpine
container_name: nginx
hostname: nginx
restart: always
ports:
- 80:80
volumes:
- ./wp.conf:/etc/nginx/conf.d/default.conf

depends_on:
- wordpress

到这里三个“service”就都定义好了,我们用docker-compose up -d启动网站,记得还是要用-f参数指定YAML文件:
1
docker-compose -f wp-compose.yml up -d

启动之后,用docker-compose ps来查看状态:

我们也可以用docker-compose exec来进入容器内部,验证一下这几个容器的网络标识是否工作正常:

1
docker-compose -f wp-compose.yml exec -it nginx sh

从截图里你可以看到,我们分别ping了mariadb和wordpress这两个服务,网络都是通的,不过它的IP地址段用的是“172.22.0.0/16”,和Docker默认的“172.17.0.0/16”不一样。

再打开浏览器,输入本机的“127.0.0.1”或者是虚拟机的IP地址(我这里是“http://192.168.10.208”),就又可以看到熟悉的WordPress界面了:

小结

好了,今天我们暂时离开了Kubernetes,回头看了一下Docker世界里的容器编排工具docker-compose。

和Kubernetes比起来,docker-compose有它自己的局限性,比如只能用于单机,编排功能比较简单,缺乏运维监控手段等等。但它也有优点:小巧轻便,对软硬件的要求不高,只要有Docker就能够运行。

所以虽然Kubernetes已经成为了容器编排领域的霸主,但docker-compose还是有一定的生存空间,像GitHub上就有很多项目提供了docker-compose YAML来快速搭建原型或者测试环境,其中的一个典型就是CNCF Harbor。

对于我们日常工作来说,docker-compose也是很有用的。如果是只有几个容器的简单应用,用Kubernetes来运行实在是有种“杀鸡用牛刀”的感觉,而用Docker命令、Shell脚本又很不方便,这就是docker-compose出场的时候了,它能够让我们彻底摆脱“命令式”,全面使用“声明式”来操作容器。

1,docker-compose是专门用来编排Docker容器的工具。

2,docker-compose也使用YAML来描述容器,但语法语义更接近Docker命令行。

3,docker-compose YAML里的关键概念是“service”,它是一个容器化的应用。

4,docker-compose的命令与Docker类似,比较常用的有up、ps、down,用来启动、查看和停止应用。

另外,docker-compose里还有不少有用的功能,比如存储卷、自定义网络、特权进程等等。

0%