持续集成是一种软件开发实践,对于提高软件开发效率并保障软件开发质量提供了理论基础,旨在提供一个开放易用的软件平台,使持续集成变成可能。为了以后方便现在把博客迁移到了Docker上面,由于只有一台机器所以这里就没有使用Docker Registry了
介绍
原理图
目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| /root/work . ├── config │ └── app.conf ├── data │ ├── leanote │ │ ├── files │ │ ├── mongodb_backup │ │ └── upload │ └── mongo ├── Dockerfile ├── jenkins └── update └── update_blog_docker.sh
|
Docker
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
安装Docker
启动服务
Jenkins
Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。
安装Jenkins
1
| docker pull docker.io/jenkins
|
启动Jenkins的容器服务
1
| docker run -d --name jenkins -p 127.0.0.1:8080:8080 -p 127.0.0.1:50000:50000 -v /root/jenkins:/var/jenkins_home jenkins
|
Dockerfile
博客的基础镜像lenoate_env
由于使用的开发版本的leanote所以自己构建了一个golang的开发环境
1 2 3 4 5 6 7 8 9
| FROM golang:1.6
MAINTAINER DuanEnJian "admin@ganktools.com"
RUN cd /go/src && wget http://golangtc.com/static/download/packages/golang.org.x.crypto.tar.gz && wget http://golangtc.com/static/download/packages/gopkg.in.mgo.v2.tar.gz && wget http://golangtc.com/static/download/packages/github.com.revel.cmd.tar.gz && wget http://golangtc.com/static/download/packages/golang.org.x.net.tar.gz && wget http://golangtc.com/static/download/packages/github.com.robfig.pathtree.tar.gz && wget http://golangtc.com/static/download/packages/github.com.revel.config.tar.gz && wget http://golangtc.com/static/download/packages/github.com.klauspost.crc32.tar.gz && wget http://golangtc.com/static/download/packages/github.com.klauspost.cpuid.tar.gz && wget http://golangtc.com/static/download/packages/github.com.klauspost.compress.tar.gz && wget http://golangtc.com/static/download/packages/github.com.agtorre.gocolorize.tar.gz && wget http://golangtc.com/static/download/packages/github.com.revel.revel.tar.gz && wget http://golangtc.com/static/download/packages/golang.org.x.sys.tar.gz && tar -zxvf golang.org.x.crypto.tar.gz && tar -zxvf golang.org.x.net.tar.gz && tar -zxvf github.com.robfig.pathtree.tar.gz && tar -zxvf github.com.revel.config.tar.gz && tar -zxvf github.com.klauspost.crc32.tar.gz && tar -zxvf github.com.klauspost.cpuid.tar.gz && tar -zxvf github.com.klauspost.compress.tar.gz && tar -zxvf github.com.agtorre.gocolorize.tar.gz && tar -zxvf github.com.revel.revel.tar.gz && tar -zxvf golang.org.x.sys.tar.gz && tar -zxvf github.com.revel.cmd.tar.gz && tar -zxvf gopkg.in.mgo.v2.tar.gz && go get github.com/revel/revel && go get github.com/revel/cmd/revel && go get gopkg.in/mgo.v2 && rm -rf golang.org.x.net.tar.gz github.com.robfig.pathtree.tar.gz github.com.revel.config.tar.gz github.com.klauspost.crc32.tar.gz github.com.klauspost.cpuid.tar.gz github.com.klauspost.compress.tar.gz github.com.agtorre.gocolorize.tar.gz github.com.revel.revel.tar.gz golang.org.x.sys.tar.gz github.com.revel.cmd.tar.gz gopkg.in.mgo.v2.tar.gz golang.org.x.crypto.tar.gz
|
博客的打包镜像
leanote自动构建的dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| FROM leanote_env
MAINTAINER DuanEnJian "admin@ganktools.com"
ADD blog.tar.gz /go/src/github.com/leanote/leanote/
COPY config/app.conf /go/src/github.com/leanote/leanote/conf/app.conf
RUN mkdir -p /leanote/data/upload/ \ && mkdir -p /leanote/data/files/ \ && mkdir -p /leanote/data/mongodb_backup/ \ && ln -s /leanote/data/upload/ /go/src/github.com/leanote/leanote/public/ \ && ln -s /leanote/data/files/ /go/src/github.com/leanote/leanote/ \ && ln -s /leanote/data/mongodb_backup/ /go/src/github.com/leanote/leanote/
VOLUME ["/leanote/data"]
EXPOSE 8081
WORKDIR /go/src
ENTRYPOINT revel run github.com/leanote/leanote prod 8081 && /bin/bash
|
自动升级脚本
update_blog_docker.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
| #!/bin/bash
WORK_DIR="/root/work"; NEW_IMAGE_NAME="leanote_"$(date +%Y%m%d%H%M%S); CURRENT_RUN_IMAGE_NAME=;
function docker_build_image(){ blog_file_path="/root/work/jenkins/workspace/Blog"; if [ ! -s ${blog_file_path} ]; then echo "[MSG]:blog source files not find !!"; exit 1; fi; cd ${blog_file_path} tar -czvf blog.tar.gz * mv blog.tar.gz ${WORK_DIR} cd ${WORK_DIR} docker build -t ${NEW_IMAGE_NAME} . if [ $? -eq 0 ]; then unlink blog.tar.gz echo "[MSG]:build images ${NEW_IMAGE_NAME} success!!"; return 0; else echo "[MSG]:build image failed !!"; exit 1; fi; }
function stop_run_blog_container(){ current_run_container_name=$(docker ps -a |awk '{print $2}' |grep ^leanote_[0-9]*[0-9]); if [ $current_run_container_name ]; then if [[ `docker ps | grep ${current_run_container_name}` ]]; then docker stop ${current_run_container_name} > /dev/null fi; if [ $? -eq 0 ]; then echo "[MSG]:stop blog container ${current_run_container_name} success !!"; CURRENT_RUN_IMAGE_NAME=${current_run_container_name}; return 0; else echo "[MSG]:stop blog container ${current_run_container_name} failed !!"; exit 1; fi; else echo "[MSG]:stop run blog container success !!"; return 0; fi }
function del_abandoned_container(){ if [ $CURRENT_RUN_IMAGE_NAME ]; then docker rm ${CURRENT_RUN_IMAGE_NAME} > /dev/null if [ $? -eq 0 ]; then echo "[MSG]:delete container ${CURRENT_RUN_IMAGE_NAME} success !!"; return 0; else echo "[MSG]:delete container ${CURRENT_RUN_IMAGE_NAME} failed !!"; exit 1; fi; else return 0; fi; }
function run_new_blog_container(){ docker run -d --name ${NEW_IMAGE_NAME} -v /root/work/data/leanote:/leanote/data --link mongo:mongo_addr -p 127.0.0.1:8081:8081 ${NEW_IMAGE_NAME} /bin/bash > /dev/null if [ $? -eq 0 ]; then echo "[MSG]:start new blog container ${NEW_IMAGE_NAME} success !!"; return 0; else echo "[MSG]:start new blog container ${NEW_IMAGE_NAME} failed !!"; exit 1; fi; }
function del_abandoned_image(){ del_image_list=$(docker images |grep ^leanote_[0-9]*[0-9] | awk '{print $1}' | sort -r | awk 'NR >2{print}'); if [ "${del_image_list}" != "" ]; then docker rmi ${del_image_list} > /dev/null if [ $? -eq 0 ]; then echo "[MSG]:del abandoned image ${del_image_list} success !!"; return 0; else echo "[MSG]:del abandoned image ${del_image_list} failed !!"; exit 1; fi; else echo "[MSG]:delete abandoned image success !!"; return 0; fi; }
function start(){ docker_build_image; stop_run_blog_container; del_abandoned_container; run_new_blog_container; del_abandoned_image; docker ps new_run_container_name=$(docker ps |awk '{print $2}' |grep ^leanote_[0-9]*[0-9]); if [ $new_run_container_name ]; then echo "[MSG]:update blog container success !!"; exit 0; else echo "[MSG]:update blog container failed !!"; exit 1; fi; }
start;
|
nginx配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| server { listen 80 default_server; server_name www.ganktools.com; location / { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
server { listen 443 ssl; server_name www.ganktools.com; ssl_certificate /opt/ssl_key/ganktools.com.crt; ssl_certificate_key /opt/ssl_key/ganktools.com.key; location / { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
server { listen 80; server_name ci.ganktools.com; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
|
配置Jenkins
Jenkins需要安装插件Git plugin,SSH plugin
系统配置
项目配置
GitHub-Api的Token获取
参考资料
Jenkins+Github持续集成
jenkins + Git 搭建持续集成环境