使用Docker+gitlab ci/cd 实现自动化部署
1. Docker
1.1 Docker是什么?
引言官网docker官网的介绍:
容器是打包代码及其所有依赖项的软件的标准单元,因此该应用程序可以从一个计算环境快速可靠地运行到另一个计算环境。Docker容器映像是轻巧的,独立的,可执行的软件软件包,其中包括运行应用程序所需的一切:代码,运行时,系统工具,系统库和设置。
容器映像在运行时会成为容器,对于Docker容器,映像会在Docker Engine上运行时成为容器。不论基础架构如何,容器化软件都可用于基于Linux和Windows的应用程序,始终运行相同。容器将软件与其环境隔离开来,并确保尽管开发和登台之间存在差异,但软件仍可以均匀运行。
在Docker Engine上运行的Docker容器:
标准: Docker创建了容器的行业标准,因此它们可以在任何地方移植
**轻巧:**容器共享计算机的OS系统内核,因此不需要每个应用程序都具有OS,从而提高了服务器效率,并降低了服务器和许可成本
**安全:**应用程序在容器中更安全,并且Docker提供了业界最强大的默认隔离功能
我的理解:
docker是一个可移植的容器,他就像一个虚拟机一样运行在我们系统中,但是比虚拟机的开销更小,在这个容器当中可以配置我们的应用环境,例如jdk环境、系统级别的环境变量等等,这样当我们需要在新的机器上部署时,我们就不需要关心环境情况,只需要安装docker我们就能愉快的跑起我们的程序,同时还能保证在多应用情况下每个应用都有一个干净的运行环境,不用担心被其他应用干扰。
1.2 Docker给我带来了什么?
1.简化了环境配置
解决了我们在部署应用时,开发环境和线上环境需要重复配置运行环境问题,达到了环境的复用,并解决了多环境下微小差异所带来的风险,降低了硬件要求和系统环境的耦合度。
2.代码流水线管理
保证了代码从开发到上线均使用一致环境。
3.隔离应用
在开发时会在一台机器上部署不同的应用,过多的应用可能互相之间产生干扰,docker可以隔离这些应用,让每个应用都运行一个干净的环境中。
4.整合服务器
Docker隔离应用的能力使得Docker可以整合多个服务器以降低成本. 由于没有多个操作系统的内存占用, 以及能在多个实例之间共享没有使用的内存, Docker可以比虚拟机提供更好的服务器整合解决方案.
5.多租户环境
多租户环境的应用中, 它可以避免关键应用的重写.我们一个特别的关于这个场景的例子是为loT(物联网)的应用开发一个快速, 易用的多租户环境. 这种多租户的基本代码非常复杂, 很难处理, 重新规划以应用不但消耗时间, 也浪费金钱.
使用Docker, 可以为每一个租户的应用层的多个实例创建隔离的环境, 这不仅简单而且成本低廉, 因为Docker环境启动的速度快, diff命令很高效.
6.快速部署
Docker为进程创建一个容器, 不需要启动一个操作系统, 时间缩短为秒级别.
可以在数据中心创建销毁资源而无须担心重新启动带来的开销. 通常数据中心的资源利用率只有30% , 通过使用Docker并进行有效的资源分配可以提高资源的利用率.
1.3 安装Docker
Docker的安装主要分为在线安装和离线安装两种方式,我这里主要采用在线安装,如果自己的机器访问不到网络可以自行百度离线安装。
需要注意,Docker要求ContOS 6以上,必须运行在64位环境当中,内核要求2.6及以上但是与3.8及以上的内核有很大差距,建议还是使用3.8以上的内核,内核必须支持并开启cgroup和命名空间功能。
1.安装Docker
yum install -y docker
2.查看Docker是否安装成功
yum list installed |grep docker
3.启动Docker
systemctl start docker
4.查看Docker启动状态 (running 则启动正常)
systemctl status docker
5.修改镜像仓库
Docker默认的仓库因为在国外下载速度很是愁人,所以在使用前建议先去找个国内的镜像仓库,我这里采用的阿里云当然还有其他很多,可自行百度。
先登录阿里云访问:https://cr.console.aliyun.com/cn-beijing/instances/images
获取到加速器地址后,先去 /ect/docker/下看看是否存在daemon.json文件,如果有直接将地址修改上去然后重启即可,如果没有参照阿里云的步骤进行创建。
1.4 编写Dockerfile生成镜像
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
详细编写规则参考:https://www.runoob.com/docker/docker-dockerfile.html
#基于 contos 7 基础镜像
FROM docker.io/centos:7
#维护人员邮箱
MAINTAINER ysl1397940314@163.com
#下载系统功能组件
# telnet 远程登陆命令组件
# nc 用于设置路由器相关参数
# wget 文件自动下载命令
# curl 综合访问命令
# unzip 解压命令
# iproute 路由操作命令
# net-tools 工具包
RUN yum install telnet nc wget curl unzip iproute net-tools -y && \
#清理yum
yum clean all && \
#删除yum缓存
rm -rf /var/cache/yum/*
#解决时区问题
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
#解决中文乱码问题
RUN yum install kde-l10n-Chinese -y
ENV LANG zh_CN.uft8
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.UFT-8 \
&& echo 'LANG="zh_CN.uft8"' > /etc/locale.conf \
&& source /etc/locale.conf
#安装jdk 1.8
COPY jdk-8u251-linux-x64.tar.gz /usr/local/
RUN tar -zxf /usr/local/jdk-8u251-linux-x64.tar.gz -C /usr/local/
RUN rm -rf /usr/local/jdk-8u251-linux-x64.tar.gz
#rm -rf /usr/local/jdk-8u251-linux-x64.tar.gz
#配置环境变量
ENV JAVA_HOME=/usr/local/jdk1.8.0_251
ENV JRE_HOME=/usr/local/jdk1.8.0_251/jre
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
ENV PATH $PATH:$JAVA_HOME/bin:$JRE_HOME/bin
#开放端口
EXPOSE 9003
#创建程序启动目录
RUN mkdir /tingwu
COPY xxx-test.jar /tingwu
#设置程序启动空间
WORKDIR /tingwu
#设置启动程序命令,注意此处一定不要使用 nohup &后台模式,否则在容器启动后会立马停止。
CMD java -server -jar xxx-test.jar -Xmsn 2048M -Xmxn 8192M
1.5 编译Dockerfile
在编写完Dockerfile需要将其编译到镜像仓库中。
创建一个docker文件夹将jdk8 和 应用程序都放在其中,因为编译时有向容器中copy的操作。
注意在编译前一定要先拉取基础镜像
docker pull centos:7
查看镜像仓库
docker images
使用build命令编译,这里注意在最后有个 .(点) 代表在当前目录编译
docker build --tag [镜像名]:[版本] -f Dockerfile .
1.6 启动docker容器
关于docker容器的一些命令:
启动容器命令, -p代表映射端口号,左边为当前服务器,右边为docker容器,不映射端口号外界无法访问该服务。
–name 容器名称 自定义
-d 代表后台启动,如果没有则会占据控制台终端
最后为你的镜像名称和版本号,注意名称前缀不要带
例如: docker.io/testname 实际名称为 testname
docker run -p 9003:9003 --name tingwu_test -d 镜像名称:版本
docker ps //查看运行中的容器信息
docker ps -a //查看所有容器信息,包含未运行的
docker rm [容器id | 容器名称] //删除该容器信息
docker start [容器id] //启动容器
docker stop [容器id] //停止容器
docker exec -it [容器id] /bin/bash //进入容器内部
通过镜像信息启动容器
docker run -p 9003:9003 --name [容器名称] -d [镜像名称]:[版本]
查看启动信息
docker ps
至此一个简单的docker容器配置启动完毕。
2. GitLab
2.1 GitLab 简介
GitLab是一个基于Git实现的在线代码仓库托管软件,你可以用gitlab自己搭建一个类似于Github一样的系统,一般用于在企业、学校等内部网络搭建git私服。
需要注意GitLab对于服务器有一定要求,建议配置在CPU2核,内存2G以上的服务器中。
在使用部署GitLab时会占用8080端口,这个需要注意。
以下是GitLab的详细介绍(引用百度百科):
GitLab是由GitLabInc.开发,使用MIT许可证的基于网络的Git仓库管理工具,且具有wiki和issue跟踪功能。使用Git作为代码管理工具,并在此基础上搭建起来的web服务。
GitLab由乌克兰程序员DmitriyZaporozhets和ValerySizov开发,它使用Ruby语言写成。后来,一些部分用Go语言重写。截止2018年5月,该公司约有290名团队成员,以及2000多名开源贡献者。GitLab被IBM,Sony,JülichResearchCenter,NASA,Alibaba,Invincea,O’ReillyMedia,Leibniz-Rechenzentrum(LRZ),CERN,SpaceX等组织使用。
2.2 GitLab 安装
因是之前安装的GitLab当时没有进行记录,所以我在网上找了一篇GitLab的安装文档,所以没有亲测,遇到问题可以给我留言或者自行百度。
2.3 GitLab-Ci/CD
GitLab-CI/CD是GitLab的一套内置的工具,主要实现了对程序开发的持续化集成、连续发布、自动化部署等功能。
以下引用官方文档进行介绍:
持续集成的工作原理是将小的代码块推送到Git存储库中托管的应用程序代码库中,并且每次推送时,都要运行脚本管道来构建,测试和验证代码更改,然后再将其合并到主分支中。
持续交付和部署包括进一步的CI,可在每次推送到存储库默认分支时将应用程序部署到生产环境。
这些方法使您可以在开发周期的早期发现错误和错误,从而确保部署到生产环境的所有代码均符合为应用程序建立的代码标准。
有关这些方法和GitLab CI / CD的完整概述,请阅读GitLab的CI / CD 简介。
2.3.1 GitLab-Ci/CD 之Runner 搭建
简介:
Runner是CI/CD中必不可少一个组件,它是我们持续化集成的实际操作者,当我们通过GitLab Service端发起操作时,实际都是分配到各个Runner服务器进行执行,Runner可以在任意服务器中部署然后再Service端中进行注册。
安装步骤:
#1.为了方便操作,请先进入到root权限
sudo su
#2.下载安装包文件
curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
#3.添加权限
chmod +x /usr/local/bin/gitlab-runner
#4.新建一个操作用户
useradd --comment 'gitlab-runner ' --create-home gitlab-runner --shell /bin/bash
#5.安装
#注意: --working-directory 是runner实际执行目录,所有从service端发起的请求命令,都会到该目录下进行执行。
gitlab-runner install --user=gitlab-runner --working-directory=[执行目录]
#6.启动
gitlab-runner start
向线上注册Runner:
打开GitLab Service端,找到CI/CD中Runners相关的东西。
找到service端的注册地址和Token
使用命令注册
gitlab-runner register
#出现下面提示,需要填写Service注册地址
#Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
#填写token
#Please enter the gitlab-ci token for this runner:
#填写备注,这个随便写
#Please enter the gitlab-ci description for this runner:
#填写tags名称,注意这个名称很重要,写的有意义一些
#Please enter the gitlab-ci tags for this runner (comma separated):
#填写执行的方式,我这里填写的shell。
#Please enter the executor: docker+machine, docker-ssh+machine, kubernetes, docker, parallels, shell, ssh, custom, docker-ssh, virtualbox:
注册完毕可以回到Service端查看Runner的信息,注意这个蓝色的标签,这个在.gitlab-ci.yaml中也会使用到。
2.3.2 .gitlab-ci.yml 文件编写
简介:
.gitlab-ci.yml文件是我们CI用来获悉我们需做什么操作的一个文件,或者说它规定了,我们的runner需要执行那些脚本或者命令。
我这里拿我编写的例子做一个简单的介绍,详细的可以参考官方文档:https://docs.gitlab.com/ee/ci/yaml/README.html。
实例:
#之前执行
before_script:
- sudo su
- source /etc/profile
#stages表示构建阶段,实际上就是规定了我们的执行流程。
#stages是按循序进行执行的,默认有三个流程就是下面build、test、deploy
stages:
- build
- test
- deploy
#这是我自己定义的一个job,他属于build流程,也就是说在执行build流程时,就会执行以下操作
heartodance:
#所属流程,与stages中的对应
stage: build
#执行的命令
script:
- mvn -v
- mvn clean
- mvn package
- ls
#停止docker容器
- sudo docker stop heartodance
#删除docker容器
- sudo docker rm heartodance
#删除docker镜像
- sudo docker rmi heartodance:demo
#生成docker 镜像
- sudo docker build --tag docker.io/heartodance:demo -f Dockerfile .
#注意,这里就是我们在runner注册时所填的tags,填那个runner的tags就意味着会在哪个runner中执行
tags:
- heartodance_test
# only表示触发机制,我这里采用了触发器触发,如果不写则代表每次提交都会触发执行
only:
- triggers
heartodance-deploy:
stage: deploy
script:
#启动容器
- sudo docker run -p 9003:9003 --name heartodance -d heartodance:demo
# - echo "sudo mkdir test"
#docker build -f Dockerfile .
tags:
- heartodance_test
only:
- triggers
2.3.2 如何查看执行?
不管我们是使用那种触发机制去执行我们CI/CD都可以在页面中的Pipelines当中查看,右边显示的每一条都代表我们此次之行的一些操作。
每一个图标都代表我们的一个job
绿色代表执行正常
红色代表失败
黄色代表执行中
点击我们执行图标可以看到详细的执行和错误信息。
3. 自动化部署思路
3.1 使用docker封装程序所需要的基础运行环境
使用docker封装一个基础环境,这样我们就不需要关心我们程序的运行环境的配置。
#--------------------------镜像说明----------------------------
#本镜像是作为heartodance的基础镜像
#本进行含有jdk 1.8的环境
#在部署时需要手动先在部署服务器中编译该镜像
#编译目录中必须包含 jdk-8u251-linux-x64.tar.gz文件
#编译命令: docker build --tag docker.io/heartodance-basis:1.0 -f Dockerfile-basis .
#------------------------------------------------------------
#基于 contos 7 基础镜像
FROM docker.io/centos:7
#维护人员邮箱
MAINTAINER ysl1397940314@163.com
#下载系统功能组件
# telnet 远程登陆命令组件
# nc 用于设置路由器相关参数
# wget 文件自动下载命令
# curl 综合访问命令
# unzip 解压命令
# iproute 路由操作命令
# net-tools 工具包
RUN yum install telnet nc wget curl unzip iproute net-tools -y && \
#清理yum
yum clean all && \
#删除yum缓存
rm -rf /var/cache/yum/*
#解决时区问题
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
#解决中文乱码问题
RUN yum install kde-l10n-Chinese -y
ENV LANG zh_CN.uft8
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.UFT-8 \
&& echo 'LANG="zh_CN.uft8"' > /etc/locale.conf \
&& source /etc/locale.conf
#安装jdk 1.8
COPY jdk-8u251-linux-x64.tar.gz /usr/local/
RUN tar -zxf /usr/local/jdk-8u251-linux-x64.tar.gz -C /usr/local/
RUN rm -rf /usr/local/jdk-8u251-linux-x64.tar.gz
#rm -rf /usr/local/jdk-8u251-linux-x64.tar.gz
#配置环境变量
ENV JAVA_HOME=/usr/local/jdk1.8.0_251
ENV JRE_HOME=/usr/local/jdk1.8.0_251/jre
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
ENV PATH $PATH:$JAVA_HOME/bin:$JRE_HOME/bin
3.2 编写程序的运行的Dockerfile
在我们的项目中编写,启动所使用的Dockerfile
注意要在根目录下,使用runner跑的时候会用到。
基于我们之前编写的basis镜像,编写运行镜像。
#基于heartodance-basis 基础镜像
FROM docker.io/heartodance-basis:1.0
#维护人员邮箱
MAINTAINER ysl1397940314@163.com
#开放端口
EXPOSE 9003
#创建程序启动目录
RUN mkdir /tingwu
COPY ./target/heartodance-1.0-DEMO.jar /tingwu
#设置启动命令
WORKDIR /tingwu
CMD java -server -jar heartodance-1.0-DEMO.jar -Xmsn 2048M -Xmxn 8192M
3.2 编写.gitlab-ci.yml 编写流程
build:
1. CI默认build流程会拉一份源码到runner本地,这个路径是在runner安装的那个工作空间中。
2.使用maven将我们源码编译成jar包,编译后的jar会在源码的target目录中
这里注意,当我们执行到deploy阶段时CI会执行默认命令删除源码中target目录,所以如果在路径中找不到也不行惊慌。
3.停止之前运行的docker容器,删除docker镜像,进行二次部署
这里的删除都是通过名字去删除的,要和Dockerfile中的一致,还有如果第一次没有的话,要手动生成镜像和启动一个容器项目
4.生成docker镜像
注意这里使用的Dockerfile就是我们项目根路径下的,镜像名称也要和删除的名称一致
docker.io/ 这是docker的一个默认前缀,创建的时候需要带上,删除和使用时不用
deploy:
1. 启动Docker 容器,这里没什么好说的,就是拉起了一个build的那个docker服务,注意映射端口就好了
总结:
通过CI的.gitlab.yaml 完成,对runner执行的规划,然后通过runner远程执行服务器上的命令,重新编译jar包,删除镜像,重新生成镜像,启动镜像。
完成了一个简版的自动部署,当然这只是第一版,后面还会对整个重新做一些调整优化。
#之前执行
before_script:
- sudo su
- source /etc/profile
- echo "heartodance build open"
stages:
- build
- test
- deploy
heartodance:
stage: build
script:
- mvn -v
- mvn clean
- mvn package
- ls
#停止docker容器
- sudo docker stop heartodance
#删除docker容器
- sudo docker rm heartodance
#删除docker镜像
- sudo docker rmi heartodance:demo
#生成docker 镜像
- sudo docker build --tag docker.io/heartodance:demo -f Dockerfile .
tags:
- heartodance_test
only:
- triggers
heartodance-deploy:
stage: deploy
script:
#启动容器
- sudo docker run -p 9003:9003 --name heartodance -d heartodance:demo
# - echo "sudo mkdir test"
#docker build -f Dockerfile .
tags:
- heartodance_test
only:
- triggers
4. 关于triggers触发器的使用
如果使用了only: triggers的方式进行触发,就意味着提交不会执行部署流程,那么怎么样触发执行那?
1. 创建一个triggers
创建triggers时备注字段可以随便填,主要是token字段。
2.使用命令进行触发
可以看到下面有很多的triggers触发的使用方式,具体使用那个可以自己来定。
主要关注的那,就是TOKEN和REF_NAME这两个参数
TOKEN = [自己创建的那个trigger的Token]
REF_NAME = 分支名称 (就是你要打那个分支的代码,我这边是主分支也就是master)