什么是CI
持续集成服务(Continuous Integration
),简称CI
。一般来说是 负责拉取代码库中的代码,然后执行我们预置定义好的一些操作脚本,然后通过一系列的编译操作构建的过程。常用工具有Gitlab CI
、Github CI
、Jenkins
、 Travis CI
等。可能大家经常看见的就是Jenkins
。
因为后续打算会推出一个从0到1,用docker + Jenkins + Kubernetes
搭建一个CI/CD
流程的文章。 本文先通过Travis CI
,进行持续集成,进行一个热身。原因就是Travis CI
开源 且 操作简单。
一、Docker
Docker
是一个开源的应用容器引擎。开发者可以将自己的应用打包在自己的镜像里面,然后迁移到其他平台的Docker
中。镜像中可以存放你自己自定义的运行环境,文件,代码,设置等等内容,再也不用担心环境造成的运行问题。镜像共享运行机器的系统内核。
同样,Docker
也支持跨平台。你的镜像也可以加载在Windows
和Linux
,实现快速运行和部署。
Docker
的优势在于 快速,轻量,灵活。开发者可以制作一个自己自定义的镜像,也可以使用官方或者其他开发者的镜像来启动一个服务。通过将镜像创建为容器,容器之间相互隔离资源和进程不冲突。但硬件资源又是共享的。 创建的镜像也可以通过文件快速分享,也可以上传到镜像库进行存取和管理。
安装 Docker
安装完Docker
后,你可能会发现自己可以打开一个Docker
的应用窗口。其实这个窗口没什么用处,通常我们都是通过CLI命令行的方式操作Docker
的,就像Git
一样。
运行 Docker
接下来我们搭建一个能够托管静态文件的 Nginx 服务器
具体步骤如下:
- 创建项目目录
- 创建 Dockerfile 文件,用其打包一个镜像 (类似前端的package.json文件)
- 镜像创建容器
- 容器运行程序
创建目录
我们创建一个 hello-docker 的目录,在该目录的根目录下 创建一个 index.html 文件:
<h1>Hello docker</h1>
然后再在目录中创建一个Dockerfile文件:
FROM nginx
COPY ./index.html /usr/share/nginx/html/index.html
EXPOSE 80
目录结构如下
hello-docker
|____index.html
|____Dockerfile
打包镜像
cd hello-docker/ # 进入刚刚的目录
docker image build ./ -t hello-docker:1.0.0 # 打包镜像
注意!Docker 中的选项(Options)放的位置非常有讲究,
docker —help image
和docker image —help
是完全不同的命令
docker image build ./ -t hello-docker:1.0.0
的意思是:基于路径./
(当前路径)打包一个镜像,镜像的名字是hello-docker
,版本号是1.0.0
。该命令会自动寻找Dockerfile
来打包出一个镜像。
运行容器
上面已经创建了镜像,接下来用这个镜像创建容器:
docker container create -p 2333:80 hello-docker:1.0.0
docker container start xxx # xxx 为上一条命令运行得到的结果
然后在浏览器打开127.0.0.1:2333
,你应该能看到刚刚自己写的index.html
内
在上边命令中
1.使用docker container create
来创建基于hello-docker:1.0.0
镜像的一个容器,使用-p
来指定端口绑定——将容器中的80
端口绑定在宿主机的2333
端口。执行完该命令,会返回一个容器ID
2.使用docker container start
启动这个容器,启动后,就能通过访问本机的2333
端口来达到访问容器内80
端口的效果了。(也可以在docker的界面操作 直接点击按钮启动容器)
当容器运行后,可以通过如下命令进入容器内部:
docker container exec -it xxx /bin/bash # xxx 为容器ID
原理实际上是启动了容器内的/bin/bash
,此时你就可以通过bash shell
与容器内交互了。就像远程连接了SSH
一样。
总结
- 写一个
Dockerfile
- 使用
docker image build
来将Dockerfile
打包成镜像 - 使用
docker container create
来根据镜像创建一个容器 - 使用
docker container start
来启动一个创建好的容器
二、Travis CI
接下来我们实战部署一个 Vuejs 写的纯静态 SPA 单页站点:
在 Github,可以有免费的 CI 资源用,它就是 Travis CI,它可以帮助我们,在我们每次更新代码时打包出一个镜像。
首先新建一个vue
项目vue create dockertest
(示例用,你们可以直接使用自己开发的小项目测试效果)react
同理。
然后在项目的根目录上 添加文件.travis.yml
内容为:
language: node_js
node_js:
- "12"
services:
- docker
before_install:
- npm install
script:
- npm run build
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- docker build -t chenjing0823/dockertest:latest .
- docker push chenjing0823/dockertest:latest
文件内容非常简单,就是使用npm run build
编译静态产出后,打包一个镜像并且push
到远程。
下面两点详细说明一下:
- 为了能够让镜像上传到服务器,你需要在
hub.docker.com
中注册一个账号,然后替换代码中的chenjing0823/dockertest:latest
,其意义对应的是用户名/包名:latest
- 使用
Github
登录Travis CI
后,在左边点击+
加号添加自己的Github
仓库后,需要移步到Setting
为项目添加DOCKER_USERNAME
和DOCKER_PASSWORD
环境变量。具体对应到上面.travis.yml
文件内脚本登录部分。 具体如下图
我们上面提到docker
打包镜像这时候就派上用场了。
同样需要在根目录上 添加Dockerfile
文件来描述如何打包docker
镜像,内容为:
FROM nginx
COPY ./dist/ /usr/share/nginx/html/
EXPOSE 80
- tips: 按照
.travis.yml
的命令次序,在打包镜像时,npm run build
已经执行过了,项目产出已经有了。不必在Docker
容器中运行npm install
和npm run build
之类的,所以直接复制文件即可。.travis.yml
内的命令次序可以参考Travis CI Tutorial
本例中的静态站点是一个SPA
单页应用,需要增加额外的Nginx
配置来保证请求都能打到index.html
。下边是编写的vhost.nginx.conf
Nginx
配置文件,将不访问文件的请求全部重定向到/index.html
:
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
proxy_set_header Host $host;
if (!-f $request_filename) {
rewrite ^.*$ /index.html break;
}
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
更新Dockerfile:
FROM nginx
COPY ./dist/ /usr/share/nginx/html/
+ COPY ./vhost.nginx.conf /etc/nginx/conf.d/dockertest.conf
EXPOSE 80
最后执行git push
后,可以在Travis CI
看到CI
的编译结果。如果编译没问题,远程实际上就有了chenjing0823/dockertest:latest
这个镜像。可以在https://hub.docker.com/
上看到镜像。
Travis CI
自动编译打包的编译结果:
同时也可以在本地试试看该镜像工作是否正常:
docker image pull chenjing0823/dockertest:latest
docker container create -p 8082:80 chenjing0823/dockertest:latest:latest
docker container start xxx # xxx 为上一条命令执行的返回值
可以通过http://localhost:8082/
看到我们的dockertest
成功运行
最后的最后,就可以登录远程VPS
服务器,安装Docker
,执行同样的命令。然后访问远程 VPS
服务器的公网IP + 8082
端口号,应该就可以看到和本地相同的效果了。
Tips: 在
VPS
上安装docker
,你可能需要参考安装教程的Linux
的安装方式.
三、Nginx 反向代理
目前已经将容器挂到了8082
端口,但是线上的环境上是不可能说让用户手动输入8082
端口访问。但是如果一股脑的直接将容器挂到80
端口上,虽然这样操作后用户可以直接不加端口直接访问,但是以后出现第二个,第三个,第n个容器呢?
这时候就需要在宿主机跑一个Nginx
,由它来独占80
端口,然后根据域名来讲请求分发给响应的容器。如下图:
这就是传说中的“反向代理”。
登录VPS
服务器,安装Nginx
此时本地通过浏览器访问VPS
的公网IP
可用看到Nginx
的欢迎页面
然后在VPS
服务器的/etc/nginx/conf.d/
中建立一个vhost.conf
文件,配置如下:
server {
listen 80;
server_name chenjing0823.info;
location / {
proxy_pass http://127.0.0.1:8082;
}
}
一个简单的配置,监听80
端口,若访问域名是chenjing0823.info(替换为你自己的域名),则全部转发到http://127.0.0.1:8082
中。配置完成后,重启 Nginx 服务器。
配置成功后,访问chenjing0823.info
会看到和VPS
公网IP:8082
相同的效果.
整个发布流程为:
- 本地修改代码,执行
git push
- 等待 CI 编译完成
- 登录
VPS
服务器,执行:
docker image pull chenjing0823/dockertest:latest
docker container create -p 8082:80 chenjing0823/dockertest:latest:latest # 得到 yyy
docker container stop xxx # xxx 为当前运行的容器ID,可用 docker container ls 查看
docker container start yyy # yyy 第二条命令返回值
网友评论