实际上,容器技术流行之后最受益的是开发者,因为开发者可以借助容器技术快速的部署好开发测试环境,也可以将自己的应用打包成一个镜像发放出去,用户可以直接拥有和开发者相同的环境,不需要繁琐的部署
容器非常适合敏捷开发模式,开发者将代码通过 svn/git 提交到远程仓库后,通过 jenkins/gitlab-ci 等持续集成工具直接构建包含最新代码的镜像,运行测试,测试成功后自动将新版本的代码的镜像滚动更新到线上环境,完全自动化,解放运维
将大型应用解耦成若干个服务模块,各服务模块松耦合,独立部署,各服务模块通过 HTTP API/RPC 通信,这种架构使得每个服务皆可以实现横向扩展,故障转移,滚动更新等高级特性,不过对于微服务来说,容器技术只是辅助,最关键的还是服务的设计
容器不是虚拟机,一般不会直接进入内部操作,打包一个镜像后,用户只需要最简单的 docker run
,需要的时候提供一些环境变量用来初始化应用即可,并不需要进入内部!
就比如 mysql 官方的镜像
$ docker pull mysql
$ docker run -d -e MYSQL_ROOT_PASSWORD=passwd mysql # 这样就可以了,直接通过外部去访问 mysql,不需要进入容器内部
相比与在 centos 上安装 mysql 需要做的步骤...
$ yum install mysql mysql-server -y
$ systemctl start mysqld
$ mysql_secure_installation
$ mysql
GRANT ALL ....
当然,这只是最简单的一个数据库安装,如果你的应用 前端用的是 nginx,后端是 mysql,还要部署 php 环境呢?假设你的应用叫做 summer-blog
$ docker pull summer-blog
$ docker run -tid -p 80:80 summer-blog
$ curl localhost:80
将复杂的环境直接打包成一个镜像,用户直接通过 docker run
就可以得到和你一样的环境,直接运行你的应用,再也不需要 *** install... 操作了
不过一般不推荐这么做,因为将那么多组件打包在一个镜像里面,无法追踪其状态
推荐分别将 nginx, mysql, php 环境独立为一个容器,再通过一些编排工具 例如 docker-compose
将每个容器连接起来
就可以使用一些很高级的功能,比如 health check
,检测到 nginx 异常退出了,自动将 nginx 容器重启,提高整个架构的可用性
Dockerfile 中有三个用来执行命令的方式,分别是 RUN、CMD、ENTRYPOINT
它们分别有什么区别呢?
-
RUN 是用来指定构建镜像(build image) 过程中执行的命令
-
CMD 是指定容器运行时(docker run) 默认命令和参数,可以被
docker run *** command
的命令所覆盖 -
ENTRYPOINT 也是容器运行时执行的命令,但是可以接受
docker run *** args
或者 CMD 提供的参数,一般用于容器配置初始化
主要是 CMD 和 ENTRYPOINT 之间的差异,一个 Dockerfile 中,如果 CMD 和 ENTRYPOINT 同时存在,那么 CMD 的会传给 ENTRYPOINT,我们来看一个例子
通过 CMD 的方式输出字符串
$ cat Dockerfile
from centos:7
CMD ["echo", "hello world"]
$ docker build . -t test
$ docker run test
hello world
如果我们想自定义输出的字符串的,可以修改 Dockerfile 重新 build 镜像,或者手动传递执行的命令,像下面这样
$ docker run test echo hello docker
hello docker
因为 CMD 是容器启动时候的默认命令,是会被 docker run image 后面的内容给覆盖的
通过 ENTRYPOINT 输出字符串
$ cat Dockerfile
from centos:7
ENTRYPOINT ["echo", "hello"]
$ docker build . -t test
$ docker run test
hello
$ docker run test world
hello world
$ docker run test echo hello world
hello echo hello world
可以看出,使用 ENTRYPOINT 之后,docker run image 后面的内容就作为位置参数传递进去了,并没有覆盖原有的命令
CMD 和 ENTRYPOINT 同时存在
$ cat Dockerfile
from centos:7
ENTRYPOINT ["echo"]
CMD ["hello world"]
$ docker build -t test
$ docker run test
hello world
会看到 CMD 也作为参数传递到 ENTRYPOINT 后面了,因为 Dockerfile 中的 CMD 其实和命令行 docker run image 后面跟的内容是等价的,但是命令行的优先级更高
$ docker run test hello python
hello python # 覆盖了 CMD
实际使用
现在比较流行的做法是 ENTRYPOINT 和 CMD 混用,ENTRYPOINT 指定一个初始化容器的脚本,CMD 指定启动前台应用的命令,我们来看看 redis 官方镜像是怎么做的
# 省略前面
COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 3306
CMD ["mysqld"]
MySQL 的 docker-entrypoint 大概的意思就是,可以手动传递一些选项,或者通过 -e 设置类似 MYSQL_ROOT_PASSWORD
这样的环境变量来初始化 MySQL