使用GitHub+Travis-CI+Docker打造自动化流水线

全文采用的是阿里云的ESC服务器,系统是CentOS 7

示例项目是NodeJS编写,本文主要是Docker的使用,在文章前2/3都是Docker命令介绍,最后我们会完成一个自动化的示例。

准备

注册账号

  1. GitHub账号

    发布项目到GitHub

  2. Travis-CI账号

    监听GitHub上项目改变,将其打包发布到DockerHub

  3. DockerHub账号

    Travis-CI将项目发布到DokcerHub时需要登陆DockerHub账号

以上账号自行注册

关于如何让Travis-CI监听到GitHub上项目的改变,请参考这篇文章

安装环境

  1. Git环境

  2. Docker环境

    安装请参考官方文档

    安装完成后,运行下面的命令,验证是否安装成功。

    $ 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/RopeHuo/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.comcloud.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

img

特别提示:这里的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

posted @ 2020-02-23 17:19  RopeHuo  阅读(1568)  评论(0编辑  收藏  举报