Docker博客环境封装及自动化部署

说来惭愧,也不记得有几次立flag要把博客坚持下去的,看看上一篇的时间,一拖又是这么久了。
为了不至于彻底沦落成上班摸鱼,下班看剧的MADAO(并非在说长谷川先生),还是想去舒适区外面逛逛。自动化部署并不是什么难事,记得以前网上就可以找到一堆TravisCI的教程。不过记得去年暑假时候使用Docker封装了博客环境,以便能在新系统上使用(Ubuntu 16.04 => 18.04),同时也是为了防止博客插件以及npm的更新引起问题。

容器内构建环境

关于Docker容器的储存结构以及基本介绍,之前貌似有一篇文章已经说了一些了,这里不再赘述。
通过镜像构建容器很简单,docker run imagename即可,由于是博客,可以把本地的blog目录挂在进去,并映射里面的端口,即加上-v /Blog:/Blog-p 4000:4000,其他设置自己怎么喜欢怎么来。
个人是直接从Docker Hub官方仓库中的ubuntu:16.04镜像来启动容器的,可以使用docker pull,也可以使用docker run命令来启动容器。
然后是安装一些必要的软件:

1
2
3
4
5
6
7
8
apt update && apt install -y vim git python wget gcc g++
wget -qO- https://raw.github.com/creationix/nvm/v0.33.11/install.sh | sh
git config --global user.email "ABCDEFG@qq.com" && \
git config --global user.name "username" && \
source ~/.profile
nvm install v9.2.1 && \
npm install hexo-cli -g && \
npm install gulp -g

首先安装必要的环境,然后安装npm的包管理工具nvm,然后配置git账号,并安装特定版本的node,在安装之前先确认之前可以运行的时候的node版本即可。剩下的就是安装hexo和gulp(博客资源压缩工具,优化用)。
为了hexo能够直接deploy,配置免密登录密钥并添加到github中。

1
ssh-keygen -t rsa -P ""

拷贝/root/.ssh/id_rsa.pub文件中内容到github的SSH-KEY中即可。
然后删掉博客中的node_modules/文件夹和db.json文件,重新安装。

1
npm install

之后便可以正常在本地访问博客了。

构建镜像

容器直接构建

在之前环境配置好之后,退出容器,将该容器打包成镜像。

1
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

可加参数有-a authorname 添加作者信息,-m message添加说明文字,如:

1
docker commit -a "Lilei && Hanmeimei" -m "blog image" CONTAINER_ID REPOSITORY:TAG

后面添加容器ID或者容器名都可以,然后添加你要上传到DockerHub的仓库名以及版本标签(TAG如果为空,默认为latest)

通过Dockerfile构建

将之前的指令写入Dockerfile文件,然后建立镜像即可。

1
2
3
4
5
6
7
8
9
10
11
12
FROM ubuntu:16.04
MAINTAINER gitever
RUN apt update && apt install -y vim git python wget gcc g++ make && \
wget -qO- https://raw.github.com/creationix/nvm/v0.33.11/install.sh | sh
ENV NVM_DIR /root/.nvm
COPY ssh /root/.ssh
RUN git config --global user.email "ABCDEFG@qq.com" && \
git config --global user.name "username" && \
. $NVM_DIR/nvm.sh && \
nvm install v9.2.1 && \
npm install hexo-cli -g && \
npm install gulp -g

其中MAINTAINER是作者名字,FROM是使用的镜像来源,然后安装环境,和之前一样。最后使用Docker build命令构建镜像。
需要说一点的是,通过Dockerfile构建的镜像不能直接使用ssh-keygen命令生成免密密钥,因为每次构建镜像时都会执行一次生成指令,如果之后版本需要修改,Dockerfile中需要加入其他指令,那么原来可以免密的镜像,生成后会变的无法登陆。最明显的就是使用ssh的方式的hexo deploy和github 仓库的访问,故而将已经可以免密的.ssh/文件夹直接拷贝进来。

1
docker build -t gitever/blog:ci .

使用-t指令是指定之后要上传到Docker Hub的镜像仓库名。
然后等待一会,会显示构建完成,使用docker images便可以查看之前直接在容器中构建的镜像和使用Dockerfile构建的镜像。通常使用Dockerfile构建镜像体积会更小,因为Docker的分层存储方式,由于在容器内通常会做很多多余的无用指令,所以直接commit构建的体积很容易变得臃肿。
之后就是上传镜像:

1
docker push gitever/blog:ci

Docker自动化部署

其实在镜像制作完成后,即可以使用镜像启动容器,然后使用博客环境了。上传镜像之后,可以在不同电脑上使用该博客环境,也不会有环境冲突的问题。但是每次都要挂载本地目录到容器中(因为博客目录体积较大,直接放入容器中体积太大,而且博客会更新,容器不能保存,只能重新制作镜像,使得效率低下)。也许是觉得在不同电脑上都要下载镜像启动容器显得麻烦,或者觉得每次都要手动generate、push和deploy显得麻烦,便开始打算使用Docker自动化部署。
首先去DockerHub创建一个仓库用来自动化部署,仓库创建需要绑定github账号,然后将博客的源文件仓库链接至该镜像仓库,如下图所示。


Docker CI

不过也不一定要链接至博客源文件仓库,可以新建一个仓库,将Dockerfile上传至该仓库,每次push该仓库触发博客自动更新也可以。直接使用博客源文件仓库则是每次写好文章push上去便直接触发更新了。
然后在本地的博客源文件(或新仓库)添加一个Dockerfile记录要自动更新的指令。

1
2
3
4
5
6
7
8
9
10
FROM gitever/blog:ci
MAINTAINER gitever
ADD .git/ /.git/
RUN git clone YourRepoUrl /Blog &&\
. $NVM_DIR/nvm.sh && \
cd /Blog && \
npm install && \
hexo cle && \
gulp && \
hexo d

然后git add .以及使用commitpush上传至git仓库即可触发。
其中,ADD一个变化的值,保证之后的构建不使用缓存,不然即使仓库更新了,容器里的仓库也不会更新。
其实不用每次git clone,git的优点就是差异性存储,所以可以之前依然可以使用缓存,节省时间,将后续操作设置成不使用缓存。

1
2
3
4
5
6
7
8
9
10
11
12
FROM gitever/blog:ci
MAINTAINER gitever
RUN git clone YourRepoUrl /Blog &&\
. $NVM_DIR/nvm.sh && \
npm install && \
ADD .git/ /.git/
RUN cd /Blog && \
. $NVM_DIR/nvm.sh && \
git pull && \
hexo cle && \
gulp && \
hexo d

另一种方式,直接将当前仓库中的文件添加到容器中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FROM gitever/blog:ci
MAINTAINER gitever
RUN mkdir /Blog
COPY _config.yml /Blog
COPY package* /Blog/
COPY gulpfile.js /Blog
COPY scaffolds/ /Blog/scaffolds
RUN cd /Blog && \
. $NVM_DIR/nvm.sh && \
npm install
ADD themes/ /Blog/themes
ADD source/ /Blog/source
ADD .git/ /Blog/.git/
RUN cd /Blog && \
. $NVM_DIR/nvm.sh && \
git pull && \
hexo cle && \
gulp && \
hexo d

这种方式,每次修改文件后都将整个文件夹添加到容器中,文件夹比较大的话会花比较多的时间。另一方面,因为Docker层层有缓存,所以第一种方式也只有第一次较慢。
Docker CI
日志
最后观察触发是否成功以及最后输出结果是否在预期内。
上述涉及到ADDCOPY区别,COPY只是简单的复制,ADD支持下载URL,并支持解压,并具有判断其ADDsrc功能。因此,在没有特殊需求时,尽量使用COPY提高效率,上述使用ADD .git/是为了让Docker Daemon判断git仓库是否更新了,如果更新了,则不使用缓存,这样,后续的git pull才能真正获取更新并最终更新到网站上。


取消缓存

此外,还可以添加.dockerignore文件来忽略一些容器中你不用的文件以提高速度。容器加载时会默认将当前目录下所有文件打包传给Docker Daemon,比如就是node_modules文件夹。
没有写的太细,长篇累牍容易给看客压力,step by step操作一番,不填坑也不会有印象,也并不会达到对容器熟悉的效果。
因为容器的方便性,我曾不断向人安利,但也许是推荐的对象不适合,用的人貌似不多,记得以前也答应过人把Docker封装环境的详细过程写写,现在算是应诺了,希望还能帮人节省一点时间。

分享
匿名评论