使用Docker来持续部署Web服务

timg.jpeg

博客架构

我的博客采用的是前后端分离架构,整体由三部分构成:博客前端、博客管理系统、博客API后端,这三个部分之间的交互全部是通过API请求进行的。这样的设计主要有以下几个原因:

  1. 博客主机配置比较弱,应尽量减少传输带宽占用和CPU负载。
  2. 前后端分离架构目前应用比较广泛,分离后的代码易于开发和测试。
  3. 这样设计并开发可以将我之前学到的一些开发技术整体应用一遍,加深理解。

整体架构题

开发流程

三个部分分别由三个代码仓库进行版本控制,由CI平台(daocloud.io)进行代码的构建与打包。每次新功能开发完毕后,使用Git命令提交到远程仓库,远程仓库利用Hook机制触发CI平台进行最新版本的代码测试与构建流程,构建完毕后进行最新版本的自动部署。由于需要在服务器上安装额外的自动部署软件,我目前没有选择将最新构建的Docker Image自动部署到我的服务器上,而是每次构建完成后手动进行部署。

时序图

Dockerfile

API服务

API服务我使用Go语言进行编写,所以Dockerfile中使用了golang的编译环境,使用alpine这个总大小只有几MB的Linux Rootfs作为运行环境。

FROM golang:alpine AS builder 

# 安装必要的编译依赖软件
RUN apk add --no-cache --virtual git musl-dev && \
    go get -u github.com/golang/dep/cmd/dep 

# 设置编译时的工作目录
WORKDIR /go/src/blog

# 将源代码拷贝到工作目录
COPY . .

# 编译源代码生成二进制文件并将其拷贝到 dist 文件夹
RUN dep ensure && go build -ldflags '-s -w' && \
    mkdir -p ../dist/ && \
    mv blog config.prod.json ../dist/


FROM alpine:latest

# 安装额外的保护软件[可选]
RUN apk add --no-cache tini

# 设置工作目录
WORKDIR /opt

# 将编译阶段所生成的可执行文件及其配置拷贝到/opt目录
COPY --from=builder ["/go/src/dist", "/opt/"]

# 声明该镜像将要使用8000端口
EXPOSE 8000

# 入口点
ENTRYPOINT ["/sbin/tini"]

# 运行参数
CMD [ "/opt/blog", "-conf", "config.prod.json"]

前端用户界面

你正在浏览的正是前端用户界面,该界面是有Nuxt(Vue系列软件)进行服务端和前端混合渲染的,它是一个独立运行的渲染服务。之所以加入服务端渲染主要考虑到搜索引擎爬虫爬取的问题,使用纯前端渲染爬虫并不能很好的抓取博客内容。博客中侧栏采用的是前端渲染,文章以及文章列表采用的是服务端渲染。

Nuxt的构建和运行需要Node环境,我们需要在Dockerfile中定义Node的执行环境。

FROM node:8.7-alpine

# 设置工作目录
WORKDIR /opt/

# 设置用于生成环境的Node ENV 参数
ENV NODE_ENV=production
ENV BASE_URL=https://0916app.com
ENV NPM_CONFIG_LOGLEVEL=warn
ENV HOST=0.0.0.0
ENV PORT=3000

# 声明该镜像所创建的容器将要使用3000端口
EXPOSE 3000

# 将源码拷贝进工作目录
COPY . .

# 安装NPM packages并构建Nuxt项目
RUN npm --registry=https://registry.npm.taobao.org install && \
    npm run build

# 入口点
CMD ["npm", "start"]

后端管理界面

博客后端管理使用Vue开发,使用Webpack打包并用Nginx作为静态资源服务器。鉴于此,Dockerfile需要定义两个环境:Node环境和Nginx环境。

FROM node:8.7-alpine AS builder

# 设置当前工作目录
WORKDIR /opt/

ENV NPM_CONFIG_LOGLEVEL=warn

# 将源代码拷贝进工作目录
COPY . .

# 安装NPM依赖并使用Webpack构建打包
RUN npm --registry=https://registry.npm.taobao.org install && \
    npm run build


FROM nginx:1.12.0-alpine

# 拷贝打包好的文件到Nginx默认静态资源目录
COPY --from=builder  ["/opt/dist", "/usr/share/nginx/html"]

可以看到,使用Dockerfile中的几行命令就可以完成工程的构建到运行环境的安装,非常方便。

配置CI,享受自动构建的乐趣

三个工程现在都创建了Dockerfile, 下一步要做的就是添加三个工程的代码仓库推送触发器到CI平台,如下图,我已经添加好了:

image.png

这样,每次提交代码到仓库都会触发自动构建过程:

WX201805181447042x.png

构建后的镜像存放在CI平台的个人镜像仓库里:

WX201805181450042x.png

如果你使用了CI平台的自动部署功能,那么此次更新就会同步更新到你的线上服务器中,如果没有使用自动部署功能则需要使用docker pull手动更新Docker镜像,进一步更新容器。