docker与git实现push-to-deploy

背景

最近在研究基于docker的持续交付过程,docker可以构建宿主机无关的软件运行环境,通过git hooks的机制(在git repo发生特定的事件时触发$GIT-DIR/hooks目录下特定的脚本),可以完成在push代码到远端的仓库的同时,构建、运行docker容器,达到push-to-deploy的目的。

实践

1. 环境:

  • 一台本地开发的机器

  • 一个第三方代码托管平台,如github、coding

  • 一台属于自己的linux服务器(用于部署)

  • 一份用于交付的代码,这里我用我最近在写的项目dockercd的后端代码,项目结构如下:《docker与git实现push-to-deploy》,项目用python flask编写,下面介绍几个主要的文件。

2. 项目

Dockerfile:用于构建整个项目的docker容器,代码如下:
FROM ubuntu
MAINTAINER jockerxu <jockerxu@**.com>
RUN sed -i 's/archive.ubuntu.com/mirrors.163.com/g' /etc/apt/sources.list
RUN apt-get update

RUN apt-get install -y apt-utils \
    && { \
        echo debconf debconf/frontend select Noninteractive; \
        echo mysql-server mysql-server/data-dir \
            select ''; \
        echo mysql-server mysql-server/root_password \
            password '123456'; \
        echo mysql-server mysql-server/root_password_again \
            password '123456'; \
        echo mysql-server mysql-server/remove-test-db \
            select true; \
    } | debconf-set-selections \
    && apt-get install -y python-pip mysql-server

RUN mkdir -pv /app
ADD . /app
WORKDIR /app
RUN pip install -r requirements.txt
expose 5000
CMD ./docker-entrypoint.sh

备注:一般情况下,docker容器一般是一个容器一个进程的原则,这里为了方便把项目代码和mysql放在同一容器中。

docker-entrypoint.sh:docker 入口脚本
_FIRST_TIME=$1
# 第一次启动容器,需要初始化数据库
if [[ $_FIRST_TIME == "true" ]]; then
    rm -rf /var/lib/mysql/*
    mysqld --initialize-insecure
    service mysql start
    mysqladmin -u root password '123456'
fi

service mysql start

python app.py

该文件主要在docker容器启动后,在容器内部启动一些服务(这里是mysql)和项目的主进程app.py。

run-project.sh:项目启动脚本
set -x
PROJECT_NAME=dockercd_backend
CONTAINER_NAME="$PROJECT_NAME"
IMG_NAME=img_"$PROJECT_NAME"
DATADIR=__data__"$PROJECT_NAME"
docker rm -f "$CONTAINER_NAME" 1>&2 2>/dev/null
docker build -t "$IMG_NAME" .
mkdir -pv "$DATADIR"
_FIRST_TIME="false"
if [[ $(ls -A "$DATADIR") == "" ]]; then
    _FIRST_TIME="true"
fi
docker run -t -d --name "$CONTAINER_NAME" -p 5000:5000 \
    -v $(pwd)/"$DATADIR":/var/lib/mysql "$IMG_NAME" \
    /bin/sh -c "./docker-entrypoint.sh $_FIRST_TIME"
set +x

这个脚本是项目的环境构建以及部署脚本,主要功能是根据Dockerfile build 出docker imags,然后从镜像启动容器并挂载数据目录$DATADIR。

项目介绍到此,下面开始利用git hooks的事件机制实现push-to-deploy。

3. git hooks

(1)登陆自己的Linux服务器,初始化一个git bare目录,初始化后以前其他项目中的.git文件夹的内容。

mkdir -pv repo.git && cd repo.git && git init --bare 

(2)在另一个文件夹中创建用于部署的目录deploy(用于git pull存放代码的目录),并通过git clone 关联第一步的repo.git

mkdir -pv deploy && cd deploy && git init
git clone ssh://username@server_ip:ssh_port/path_to/repo.git

(3)回到repo.git文件夹,编辑hooks/post-receive(默认不存在这个文件),这个文件就是一个shell脚本,当有代码git push到这个仓库的时候触发,内容如下

unset GIT_DIR
DeployPath=/path_to/deploy
 
set -x
cd $DeployPath
git add . -A && git stash
git pull origin master
echo "pull code done"
./run-project.sh
echo "deploy done"
set +x  

主要功能就是进入部署的目录,拉取代码,通过./run-project.sh启动项目。

(4)来到自己的本地开发机,通过git clone 获取自己在github或者coding上项目的代码,这里我的项目是上面提到的dockercd_backend,向项目添加一个远程仓库(这里是我们自己服务器的repo.git),然后提交代码到my_server的repo.git,触发hooks/post-receive脚本,deploy目录开始拉取代码进行部署。

git clone from_github_or_coding
git remote add my_server ssh://username@server_ip:ssh_port/path_to/repo.git
git push my_server master

至此,push-to-deploy完成。

    原文作者:晨晖
    原文地址: https://segmentfault.com/a/1190000009869700
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞