全文采用的是阿里云的ESC服务器,系统是CentOS 7
示例项目是NodeJS编写,本文主要是Docker的使用,在文章前2/3都是Docker命令介绍,最后我们会完成一个自动化的示例。
准备
注册账号
GitHub账号
发布项目到GitHub
Travis-CI账号
监听GitHub上项目改变,将其打包发布到DockerHub
DockerHub账号
Travis-CI将项目发布到DokcerHub时需要登陆DockerHub账号
以上账号自行注册
关于如何让Travis-CI监听到GitHub上项目的改变,请参考这篇文章
安装环境
Git环境
Docker环境
安装请参考官方文档
- Mac
- Windows
- Ubuntu
- Debian
- CentOS
- Fedora
- 其他 Linux 发行版
安装完成后,运行下面的命令,验证是否安装成功。
$ docker version # 或者 $ docker info
Docker 需要用户具有 sudo 权限,为了避免每次命令都输入
sudo
,可以把用户加入 Docker 用户组(如果你是root用户的话就不需要了)$ sudo usermod -aG docker $USER
Docker 是服务器----客户端架构。命令行运行
docker
命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动,这是Linux下启动服务方式。# service 命令的用法 $ sudo service docker start # systemctl 命令的用法 $ sudo systemctl start docker
正文
了解Docker
首先学习下Docker
的两个核心知识点
container
(容器)和image
(镜像)
Docker
的整个生命周期由三部分组成:镜像(image
)+容器(container
)+仓库(repository
)
每台宿主机(电脑),他下载好了Docker
后,可以生成多个镜像,每个镜像,可以创建多个容器。发布到仓库(比如DockerHub)时,以镜像为单位。可以理解成:一个容器就是一个独立的虚拟操作系统,互不影响,而镜像就是这个操作系统的安装包。想要生成一个容器,就用安装包(镜像)生成一次,这就是Docker
的核心概念。
# 列出本机的所有 image 文件。
$ docker image ls
# 删除 image 文件
$ docker image rm [imageName]
image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库 Docker Hub 是最重要、最常用的 image 仓库。
image
国内连接 Docker 的官方仓库很慢,还会断线,需要将默认仓库改成国内的镜像网站
推荐使用官方镜像 registry.docker-cn.com 。下面是 CentOS 系统的默认仓库修改方法,其他系统的修改方法参考官方文档。
打开/etc/default/docker
文件(需要sudo
权限),在文件的底部加上一行,如果没有该文件可以自己创建。
DOCKER_OPTS="--registry-mirror=https://registry.docker-cn.com"
然后,重启 Docker 服务。
$ sudo service docker restart
现在就会自动从镜像仓库下载 image 文件了。
container
image 文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。
# 列出本机正在运行的容器
$ docker container ls
# 列出本机所有容器,包括终止运行的容器
$ docker container ls --all
上面命令的输出结果之中,包括容器的 ID。很多地方都需要提供这个 ID,
使用docker container kill
命令可终止容器运行
$ docker container kill [containID]
终止运行的容器文件,依然会占据硬盘空间,可以使用docker container rm
删除。
$ docker container rm [containerID]
运行上面的命令之后,再使用docker container ls --all
命令,就会发现被删除的容器文件已经消失了。
Dockerfile 文件
学会使用 image 文件以后,接下来的问题就是,如何可以生成 image 文件?如果你要推广自己的软件,势必要自己制作 image 文件,这就需要用到 Dockerfile 文件。它是一个文本文件,用来配置 image。Docker 根据 该文件生成二进制的 image 文件。
下面通过一个实例,介绍什么是 Dockerfile 文件。
实例
下面我以 这个项目 为例,介绍什么是 Dockerfile 文件,实现让用户在 Docker 容器里面运行 Koa 框架。
在你的服务器上克隆该项目(如果没有Git环境记得安装)
$ git clone https://github.com/mufengsm/travis-ci
$ cd travis-ci
.dockerignore文件
.git
node_modules
npm-debug.log
上面代码表示,这三个路径要排除,不要打包进入 image 文件。如果你没有路径要排除,这个文件可以不要
Dockerfile文件
# 该 image 文件继承官方的 node image,冒号表示标签,这里标签是8.4,即8.4版本的 node。
FROM node:8.4
# 将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入 image 文件的/app目录。
COPY ./ /app
# 指定接下来的工作路径为/app。
WORKDIR /app
# 在/app目录下,运行npm install命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。
RUN npm install --registry=https://registry.npm.taobao.org
# 将容器 3000 端口暴露出来, 允许外部连接这个端口。
EXPOSE 3000
# 这一行表示等运行image时在shell中自动输入的命令,不用我们自己再去node文件了。
CMD node hello.js
现在我们服务器上有Dokcer环境,我们通过下面的命令创建image文件
# -t参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是latest。
$ docker image build -t travis-ci ./
# 或者
$ docker image build -t travis-ci:0.0.1 ./
如果运行成功,就可以看到新生成的 image 文件travis-ci
了。
$ docker image ls
生成容器
docker container run
命令会从 image 文件生成容器。
# 3000端口是上面Dockerfile文件中暴露的,8000端口是自定义的可以通过外网访问
# -p参数:容器的 3000 端口映射到本机的 8000 端口
# -it参数:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器
# travis-ci:0.0.1:image 文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)
# /bin/bash:容器启动以后,内部第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell
# /bin/bash也属于CMD命令他会覆盖我们Dockerfile文件中的CMD命令,两者只能选一
$ docker container run -p 8000:3000 -it travis-ci /bin/bash
# 或者
$ docker container run -p 8000:3000 -it travis-ci:0.0.1 /bin/bash
如果一切正常,运行上面的命令以后,就会返回一个命令行提示符。
[你的服务器名称]:/app#
这表示你已经在容器里面了,返回的提示符就是容器内部的 Shell 提示符。执行下面的命令。
node hello.js
这时,Koa 框架已经运行起来了。打开浏览器,访问 [你的域名/ip]:8000,网页显示"hello world"
这个例子中,Node 进程运行在 Docker 容器的虚拟环境里面,进程接触到的文件系统和网络接口都是虚拟的,与本机的文件系统和网络接口是隔离的,因此需要定义容器与物理机的端口映射(map)。
现在,在容器的命令行,按下 Ctrl + c 停止 Node 进程,然后按下 Ctrl + d (或者输入 exit)退出容器。此外,也可以用docker container kill
终止容器运行。
# 列出所有容器,不加 -a 仅列出正在运行的,像退出了的或者仅仅只是创建了的就不列出来
$ docker ps -a
# 在本机的另一个终端窗口,列出当前运行的容器,查出容器的 ID
$ docker container ls
# 停止指定的容器运行
$ docker container kill [containerID]
容器停止运行之后,并不会消失,用下面的命令删除容器文件。
# 查出容器的 ID
$ docker container ls --all
# 删除指定的容器文件
$ docker container rm [containerID]
CMD 命令
容器启动以后,需要手动输入命令node hello.js
。我们可以把这个命令写在 Dockerfile 里面,这样容器启动以后,这个命令就已经执行了,不用再手动输入了。
FROM node:8.4
COPY ./ /app
WORKDIR /app
# RUN
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 3000
# CMD
CMD node hello.js
上面有RUN命令和CMD命令,RUN
命令与CMD
命令的区别在哪里?简单说,RUN
命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;CMD
命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个RUN
命令,但是只能有一个CMD
命令。
注意,指定了CMD
命令以后,docker container run
命令就不能附加命令了(比如前面的/bin/bash
),否则它会覆盖Dockerfile中的CMD
命令。现在,启动容器可以使用下面的命令。
# 这里多了一个--rm,意思是在容器终止运行后自动删除容器文件。
$ docker container run --rm -p 8000:3000 -it travis-ci:0.0.1
发布image
手动发布
首先,去 hub.docker.com 或 cloud.docker.com 注册一个账户。然后,用下面的命令登录。
$ docker login
接着,为本地的 image 标注用户名和版本。
$ docker image tag [image名称] [你的用户名]/[仓库名]:[标签]
# 例子
$ docker image tag travis-ci:0.0.1 rope/travis-ci:0.0.1
也可以不标注用户名,重新构建一下 image 文件即可。
# 记得进入项目目录后再操作
$ docker image build -t [username]/[repository]:[tag] ./
最后,发布 image 文件。
$ docker image push [username]/[repository]:[tag]
发布成功以后,登录 hub.docker.com,就可以看到已经发布的 image 文件。
自动发布
我们使用gitHub+travis+docker
来形成一套完整的自动化流水线
只要我们push新的代码到gitHub上,自动帮我们构建出新的代码发布到DockerHub,然后我们拉取新的镜像即可
首先我们先进入 Travis CI 官网配置,注册绑定自己的gitHub账号,然后在左侧将自己需要git push
后自动构建镜像的仓库加入可参考这篇文章
我们继续使用上面用到的travis-ci项目,为了验证我们下面的操作是成功的可以将项目中的hello.js显示的hello world改成其他内容。
查看 .travis.yml 文件
language: node_js
node_js:
- '12'
services:
- docker
before_install:
- npm install
script:
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- docker build -t mufengsm/travis-ci:latest .
- docker push mufengsm/travis-ci:latest
注意 :mufengsm/travis-ci
应该换成你的用户名/包名,再push
代码
每次push
代码到GitHub,Travis-CI都会下载,然后根据package.json
文件下载所需包,再登陆DockerHub账户,再打包并发布到DockerHub,这样你下载的镜像就是有最新的代码。
打开travis-ci中所监听GitHub项目的设置页面,然后添加两个环境变量,这个用户名和密码和你的DockerHub账户是对应的:
DOCKER_USERNAME和DOCKER_PASSWORD
特别提示:这里的Docker
容器,想要后台运行,就必须有一个前台进程。容器运行的命令如果不是那些一直挂起的命令(比如tcp,ping,node
),就是会自动退出的,通过 docker ps -a
可以看到容器关闭的原因
当配置成功,代码被推送到GitHub
上后,travis-ci
帮我们自动构建发布新镜像
一定要学会使用: docker ps -a
查看容器的状态
至此,发布,自动构建镜像已经完成
拉取新的镜像
正式开始拉取镜像,启动容器
我们刚才发布的镜像名称是:mufengsm/travis-ci
清除镜像和容器
如果在此之前你创建了很多镜像和容器,一个个删除又太麻烦,下面的命令可以帮到你。
# docker中 启动所有的容器命令
docker start $(docker ps -a | awk '{ print $1}' | tail -n +2)
#docker中 关闭所有的容器命令
docker stop $(docker ps -a | awk '{ print $1}' | tail -n +2)
#docker中 删除所有的容器命令
docker rm $(docker ps -a | awk '{ print $1}' | tail -n +2)
#docker中 删除所有的镜像
docker rmi $(docker images | awk '{print $3}' |tail -n +2)
#tail -n +2 表示从第二行开始读取
然后使用:
$ docker image pull mufengsm/travis-ci:latest
拉取镜像,这时候需要下载,拉取完成后,使用docker images
可以看到mufengsm/travis-ci:latest
镜像已经存在了
我们使用
# --rm参数,在容器终止运行后自动删除容器文件。
$ docker container run --rm -p 8000:3000 -it mufengsm/travis-ci:latest
创建这个镜像的容器,并且绑定在端口号8000
上
浏览器输入 [你的域名/ip]:8000
发现,访问成功。
最后
我们再梳理下整个流程,创建项目,创建Dockerfile文件,创建travis.yml文件,发布到GitHub,Travis-CI监听项目,自动打包发布到DockerHub,拉去新的镜像,再运行。
参考文章
https://segmentfault.com/a/1190000020676601
http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html