一、前言#
为什么还学Docker的容器编排?
kubernetes几年前就是容器编排的龙头老大了,感觉上想学容器编排,是不是可以直接去学学k8s了呢?
其实我是学了一阵k8s之后折回头实践使用一下Docker容器编排的,因为在学k8s的过程中难免总是和Docker的容器编排做对比。所以不学学Docker Swarm,怎么知道K8S才是最好用、最强大的容器编排工具呢?
所以整理笔记 记录实战Docker Compose和Docker Swarm
二、Docker Compose#
2.1、简介#
Docker Compose 是Docker提供的定义、运行多个Docker应用容器的工具,我们通过Docker Compose定义配置好应用服务后,通过一条简单的命令就能根据这个配置创建出配置中描述的容器。
Docker Compose可以运行在生产环境、测试环境和开发环境中。
使用Docker Compose需要有这三个基础的步骤:
- 使用Dockerfile定义你的应用环境。
- 编写docker-compose.yml 定义你的服务,目的是为了让Dockerfile定义的容器可以一起运行。
version: '2.0' services: # 描述我们的应用 web: build: . ports: - "5000:5000" volumes: - .:/code - logvolume01:/var/log links: # 在启动前先启动redis - redis redis: image: redis volumes: # 持久化相关挂载卷 logvolume01: {}
- 执行
docker-compose up
命令,Compose就会开始运行你描述的整个app。
参考:官方文档:https://docs.docker.com/compose/
2.2、下载安装#
# 将docker-compose下载安装到 /usr/local/bin 目录下 curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# docker-compse是一个二进制可执行的文件,所以给他可执行权限 sudo chmod +x /usr/local/bin/docker-compose
2.3、小实验#
在这个小实验中,我们将使用Docker Compose安装一个简单的Java Web应用。
Java Web使用SpringBoot极速构建,提供一个Restful方法如下:
每次调用它都将redis里面的key=money的值+1后返回~
编写Dockerfile,这个dockerfile可以让我们将应用都jar包打包成 docker image
编写docker compose。这个描述文件就是在告诉docker-compose按照什么都规则去启动构建容器。
将 Dockerfile、docker-compose.yml、jar包都上传到服务器上~
为什么这里写服务名,而不写ip?
因为docker容器启动后会随机分配给它ip,举个例子:比如你有两个镜像A、B,那先如果先启动A,那他的ip可能是:172.16.0.2 。再启动B他的ip就可能是 172.16.0.3。 反之:如果你先启动的是容器B,那他的ip可能是172.16.0.3,而不是我们一开始说的172.16.0.2
所以这里写服务名是一个明智的选择,因为如果我们在这里固定写一个ip的话,万一哪天这个容器挂了,被重新拉起之后他的ip变了,那我们的web应用岂不是找不到这个redis了?所以用不会服务名替换ip。很明智。
容器启动后,同属一个网络下(默认一般是桥接)的容器彼此能根据对方的name彼此ping通。
使用docker-compose时,他会为我们新创建一个虚拟网卡。app中的容器启动后都会加入这个虚拟网络中。
对这块知识有疑问,可以看看这篇笔记:https://www.cnblogs.com/ZhuChangwu/p/13689736.html
web项目的配置文件如下图:
redis的host并不是某一个ip哦,而是一个服务名~
构建启动:应用服务
这其实是一个比较激动人心的事情。可以想一下,原来学docker的时候,我们直接从docker-hub上下载镜像,然后: docker run 使用镜像。
后来我们学着通过volume将容器中应用的配置文件挂载到宿主机实现简单的定制化配置,然后docker run 启动容器
再后来我们学习了Dockerfile,自定义镜像,实现了将我们本地打包好的应用做成镜像,然后docker run 启动容器。
到现在,我们下载安装好docker后,不用手动下载任何镜像,只要编写Dockerfile描述我们打包好后到程序应该做成什么镜像,通过docker-compose.yml 描述组成app的各个容器(可以是Dockerfile描述的镜像、本地已经存在的镜像、或者远程仓库中的镜像)之间有什么依赖关系。谁先启动,谁后启动。然后执行 docker-compose up命令,一键部署app。
# 一键部署 [root@VM-0-6-centos myServer]# docker-compose up # docker-compose为我们创建了一叫做: myserver_default的网络 Creating network "myserver_default" with the default driver # 构建web模块时,发现他depend_on redis,所以先拉去redis镜像 Pulling redis (redis:)... latest: Pulling from library/redis d121f8d1c412: Pull complete 2f9874741855: Pull complete d92da09ebfd4: Pull complete bdfa64b72752: Pull complete e748e6f663b9: Pull complete eb1c8b66e2a1: Pull complete Digest: sha256:1cfb205a988a9dae5f025c57b92e9643ec0e7ccff6e66bc639d8a5f95bba928c Status: Downloaded newer image for redis:latest # 开始构建docker-compose.yml中指定的web模块 Building web Step 1/5 : FROM java:8 8: Pulling from library/java 5040bd298390: Pull complete fce5728aad85: Pull complete 76610ec20bf5: Pull complete 60170fec2151: Pull complete e98f73de8f0d: Pull complete 11f7af24ed9c: Pull complete 49e2d6393f32: Pull complete bb9cdec9c7f3: Pull complete Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d Status: Downloaded newer image for java:8 ---> d23bdf5b1b1b Step 2/5 : COPY *.jar /app.jar ---> 15421d081257 Step 3/5 : EXPOSE 8888 ---> Running in 18f52319a82d Removing intermediate container 18f52319a82d ---> 86cb853b5711 Step 4/5 : CMD ["--server.port=8888"] ---> Running in 147d797d5848 Removing intermediate container 147d797d5848 ---> 323a85aa9c61 Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"] ---> Running in 6988142d65d4 Removing intermediate container 6988142d65d4 ---> 245e7675226d Successfully built 245e7675226d Successfully tagged myserver_web:latest WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`. # 为我们的webapp成功创建了两个容器 Creating myserver_redis_1 ... done Creating myserver_web_1 ... done Attaching to myserver_redis_1, myserver_web_1 # 先启动redis redis_1 | 1:C 21 Sep 2020 12:27:54.827 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo redis_1 | 1:C 21 Sep 2020 12:27:54.827 # Redis version=6.0.8, bits=64, commit=00000000, modified=0, pid=1, just started redis_1 | 1:C 21 Sep 2020 12:27:54.827 # 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 21 Sep 2020 12:27:54.828 * Running mode=standalone, port=6379. redis_1 | 1:M 21 Sep 2020 12:27:54.828 # 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 21 Sep 2020 12:27:54.828 # Server initialized redis_1 | 1:M 21 Sep 2020 12:27:54.828 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. redis_1 | 1:M 21 Sep 2020 12:27:54.828 # 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 madvise > /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 (set to 'madvise' or 'never'). redis_1 | 1:M 21 Sep 2020 12:27:54.828 * Ready to accept connections # 启动SpringBoot web_1 | web_1 | . ____ _ __ _ _ web_1 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ web_1 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ web_1 | \\/ ___)| |_)| | | | | || (_| | ) ) ) ) web_1 | ' |____| .__|_| |_|_| |_\__, | / / / / web_1 | =========|_|==============|___/=/_/_/_/ web_1 | :: Spring Boot :: (v2.3.4.RELEASE) web_1 | web_1 | 2020-09-21 12:27:56.777 INFO 1 --- [ main] com.changwu.DemoApplication : Starting DemoApplication v0.0.1-SNAPSHOT on b66d5414a322 with PID 1 (/app.jar started by root in /) web_1 | 2020-09-21 12:27:56.780 INFO 1 --- [ main] com.changwu.DemoApplication : No active profile set, falling back to default
服务启动后可以验证一下 docker-compose up命令是否构建起了我们的服务
停止服务:
- 在yml文件所在目录执行:
docker-compose stop
- CTRL + C
docker-compose up 运行起所有的容器后,我们得到的是一个project,注意这里的这个project依然是一个单机的应用,相对于拆分前来说,现在的project是一个容器化后的单机应用。 (Docker提供的集群化部署方案在下面的章节~)
官方Demo:https://docs.docker.com/compose/gettingstarted/
2.4、小实验的细节#
docker-compose up 成功执行后,可以看到他根据我们配置文件描述,为我们自动下载了redis镜像、java镜像、以及根据Dockerfile创建镜像
查看当前正在运行的容器(通过 docker-compose up 为我们自动运行起来的容器):
正在运行的容器的命名规则:目录名_镜像名_副本数
docker-compose up 命令还为我们创建了一个叫做 composetest_default的网络,整个项目中的容器都加入到这个网络中,这个网络支持我们使用 服务名访问到容器。是实现负载均衡的前提。
查看网络的详情:下面的两个容器在同一个网络下,
在同一个网络下的容器,彼此是可以通过对方的服务名访问到对方,如下:
2.5、Compose file的编写规则#
参考:https://docs.docker.com/compose/compose-file/