面向个人开发者应该打造的CICD部署系统

11,282 阅读17分钟

作为一个个人开发者,在业余时间也会想着开发一些个人的好玩的项目,去开发一些效率工具,开发一些自己喜欢的程序,在这个前提下,很多人购买了自己的服务器,作为一个前端开发,在最开始的时候对服务器相对会比较陌生,如果接触不多,在部署自己的项目过程中也会有许许多多的不便,我们也可以为自己搭建一套自动化部署,能够让我们在开发个人项目的时候享受同样的便捷。

在市面上,自动化部署的方案有很多,也接触到过不同的部署方案,在前公司,由于公司后端的主要技术栈是java,于是便使用的是Jenkins方案,因为Jenkins 是一款著名的可扩展的用于自动化部署的开源 CI/CD 工具。Jenkins 是完全用 Java 编写的。而目前的公司呢,后端技术栈是golang,于是目前采用了docker+gitlab的方案,感觉这也是市面上两个相对覆盖面较咣的部署方案,各有差异但个人觉得差异也不是特别大,本文想要介绍得是后者。

面向用户

本文想分享的是作为一个个人开发者如何能搭建一套适合个人使用的cicd,而不是企业级别,对于个人开发者而言,我们大多只有一台服务器,而在企业当中一般都会搭配集群使用,两种的差别相对较大,而对于开发者如果只要一台服务器的场景下,我们需要考虑到一些其他问题,比如:端口占用,多项目部署等问题,所以,本文是一个从0到1快速构建个人cicd的教程。看过很多市面上的教程,大多更像是笔记一样,很多坑并没有列出来且解决方案也比较单一,不够详细,所以才会在这里记录一篇相对比较详细容易理解的教程。

什么是cicd

CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。CI/CD 的核心概念是持续集成、持续交付和持续部署。它是作为一个面向开发和运营团队的解决方案,主要针对在集成新代码时所引发的问题(也称为:“集成地狱”)。

CI/CD 可让持续自动化和持续监控贯穿于应用的整个生命周期(从集成和测试阶段,到交付和部署)。

这些关联的事务通常被统称为 CI/CD 管道,由开发和运维团队以敏捷方式协同支持。

其次我们要将其拆开来读CICD实际是两部分构成,我们需要在学习前掌握这些最基本的概念。一般我们称CI[## CI 持续集成(Continuous Integration)]CD[ 持续交付(Continuous Delivery)] 也可以说是CD[]CD 持续部署(Continuous Deployment) ,毕竟项目的最终流程一定是部署上线,它是作为持续交付的延伸,持续部署可以自动将应用发布到生产环境。我们一般称之为自动化部署,在我们的工单中的直观感受就是,当你git push代码之后就无需关心接下来的环节了,他会由系统自动走完CI最终自动部署到服务器上去,我们要实现的就是这样的东西。

简述

从大的点来看,在开始搭建前我们简单的介绍一些基于docker+gitlab这套自动化部署的基本流程,首先我们需要安装docker,毕竟我们就是基础docker 来实现的,其次我们需要在服务器上部署社区版的gitlab,可以理解为私有的gitlab,我们可以把自己的项目上传到上面去,当我们上传推送项目之后,则会触发ci操作,而需要这个操作,我们需要基于gitlab-runner来实现,从大的角度来看就只有这三步即可:

  1. 安装docker
  2. 安装gitlab
  3. 安装gitlab-runner

准备工作

在开始搭建之前,我们需要准备这些东西,要部署上线最基本的是离不开一台个人服务器,需要注意的是,gitlab对服务器性能要交较高,最低要求配置2h4g,但是个人体验发现依然有点小了,推荐使用4h8g服务器来搭建才能保证其稳定性,前期学习测试可以去开通一个按量付费的服务器来使用相对比较划算。同时尽量提前去开启端口的访问权限,如果是初次尝试就打开所有端口方便后续测试,如果已经尝试过一次,就打开所需端口即可。

本教程使用的是centos系统的服务器

其次可以准备一个域名,当然这并不强制,准备的东西相对简单,主要还是需要一台性能比较ok的服务器,接下来我们正式开始:

安装docker

需要注意的是,不同系统的服务器安装会有异同,详情可看官方文档:

首先,我们连接上自己的服务器:

检查服务器系统版本
cat /etc/redhat-release #docker 需要使用7+版本
如果有旧版本卸载旧版本

如果你不是全新的服务器,建议检查下之前是否安装过,如果安装过需要先卸载掉,如果是全新的服务器,那么可以忽略。

yum remove docker docker-common docker-selinux docker-engine docker-ce docker-ce-cli containerd.io
首先安装yum-utils

yum-utils是管理repository及扩展包的工具 (主要是针对repository)

yum install yum-utils
更改镜像源

网络原因,很多时候会不稳定,这里源的选择比较多,下面这个是阿里云的镜像

yum-config-manager \
>     --add-repo \
>     https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
缓存yum

我们在更新yum源或者出现配置yum源之后,通常都会使用yum makecache 生成缓存,这样可以在下次更快,yum 会把下载的软件包和header存储在cache中而不自动删除。如果觉得占用磁盘空间,可以使用yum clean指令清楚缓存。

yum makecache fast
安装Docker Engine引擎
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
启动docker
sudo systemctl daemon-reload 
sudo systemctl start docker
设置开机自启动
sudo systemctl enable docker
检查是否安装成功
docker version

如果不出意外,按照上述步骤已经成功安装了docker,如果你对docker还不了解,可以尝试看看这篇文档,🎉 Docker 简介和安装 - Docker 快速入门,后续也会再写一篇关于docker的详细文章,在这个教程里,我们暂时只需要会用即可。安装完docker我们需要安装下一项了。

安装 gitlab

首先我们需要知道的是我们是采用docker容器化的方式安装,所以其实拉取的是镜像进行部署,但是镜像会有很多,我们可以

查看所有可用的gitlab镜像
docker search gitlab

可以看到应该会有非常多的镜像,这里为大家列出两个。

拉取gitlab镜像
  1. 英文版本镜像

    docker pull gitlab/gitlab-ce
    
  2. 中文版本镜像

    docker pull twang2218/gitlab-ce-zh
    

这里是单纯的拉取镜像,中文版还是英文版大家自己决定,没有太大差异

启动gitlab
sudo docker run --detach \
 --hostname ip/域名 \
 --publish 443:443 --publish 80:80 --publish 222:22 \
 --name gitlab \
 --restart always \
 --volume /srv/gitlab/config:/etc/gitlab \
 --volume /srv/gitlab/logs:/var/log/gitlab \
 --volume /srv/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce

上面这条就是用docker启动gitlab的命令,也是搜索上大量教程看到的,这里先简单介绍一下上面的参数:

  1. hostname这里可以填写服务器ip 如果你有域名也可以填写域名。
  2. publish对应的分别是 http访问端口https访问端口代码ssh推送端口
  3. name是docker容器自己起的名
  4. restart表示重启gitlab的时候自动重启容器
  5. volume 目录挂载映射
  6. 最后一行则是镜像名称,推荐使用上面所列的两个镜像,二选一替换即可

注意:正常情况这样我们可以启动gitlab,但是需要注意的是,gitlab默认使用的就是80和443端口,占用了这两个端口将会在后续带了很多不便,由于我们只有一个服务器,这样就导致后续我们部署任何项目都得域名+端口访问了,因为后续我们去使用nginx就没办法挂在80端口了,所以如果是个人开发者,只有一台服务器的情况下使用默认端口,所以,我们为其修改一下端口配置:

sudo docker run --detach \
 --hostname ip/域名 \
 --publish 8088:8088 --publish 8089:8089 --publish 222:22 \
 --name gitlab \
 --restart always \
 --volume /srv/gitlab/config:/etc/gitlab \
 --volume /srv/gitlab/logs:/var/log/gitlab \
 --volume /srv/gitlab/data:/var/opt/gitlab \
twang2218/gitlab-ce-zh

执行以上命令,docker就会以容器的形式启动gitlab了,需要注意的是,这是异步启动,gitlab的启动时间相对还是比较长的,我们可以

查看容器日志
docker logs -f gitlab # gitlab是容器自己起的名字

可以看日志,启动完成我们就可以通过ip:8089访问到gitlab了。

注意 gitlan第一次打开会让你设置管理员的密码,输入完密码就可以登录了,用户名是root密码是你输入的。如果你刷新了页面,那么系统就会随机生成一个密码,这个时候就需要自己去配置文件看密码或者自己修改一个密码了,如果你不幸如此,那么请看下一段,如果你设置成功了,请跳过

如何自定义设置管理员密码

如果在打开页面首次没有让你设置密码,那我们可以进入容器内部进行自定义设置

# 1.进入容器
docker exec -it gitlab bash
# 2.进入控制台
gitlab-rails console production
# 3.查询root账户信息
user  =  User.where(id: 1).first
# 4.重置密码 最低八位数
user.password='88888888'
# 5.二次确认密码
user.password_confirmation='88888888'
# 6.保存
user.save!
# 7.退出
quit

# 还有一种是直接进入容器显示密码,但是发现不同的版本不一定生效就不推荐了,直接使用这种方式修改也很方便

简单的几步即可设置完root账户密码,接下来就可以尝试登录了

如果不出意外的话这个时候你就看到了日常使用的gitlab一样的界面了,里面的操作不用多说了,和使用其他的代码管理工具并无太大差别。

到此为止,我们仅仅是完成了一个私有Gitlab的搭建工作,接下来我们需要配合gitlab-renner来完成我们的工作。

什么是Gitlab-renner

GitLab Runner是一个开源项目,用于运行您的作业并将结果发送回GitLab。它与GitLab CI一起使用,GitLab CI是GitLab随附的开源持续集成服务,用于协调作业。

GitLab Runner是用Go编写,可以作为单个二进制文件运行,不需要语言特定的要求。

gitlab-renner有三种状态

  1. shared:运行整个平台项目的作业(gitlab)
  2. group:运行特定group下的所有项目的作业(group)
  3. specific:运行指定的项目作业(project)

这里大致了解就好,初次来开发属于我们个人的cicd平台,我们可以先不用考虑其中暂时优先级不高的内容,建议在基本走完一套流程之后再回过头了看看。

安装gitlab-runner

我们之间用docker镜像启动即可,这里基本都是一样,可以去官网看看没有区别

sudo docker run -d --name gitlab-runner --restart always \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest

安装完gitlab-renner并成功运行后,我们此时需要将gitlab和gitlab-renner之间产生关联,所以我们需要注册runnergitlab

注册runner

因为注册的runner是gitlab的,所以注册的时候我们需要进到容器内

docker exec -it gitlab-runner bash

上面的gitlab-runner是我们定义的容器名称,替换成其他名称也可以进入其他容器,如果你是根据我们的流程进行的,那么这里就无需理会。

docker run --rm -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register \
--non-interactive \
--executor "docker" \
--docker-image alpine:latest \
--url "http://gitlab.xxxx.com:9880/" \
--registration-token "i-WPBnBbQtiQDYndpQkc" \
--description "my first nine-runner" \
--tag-list "nine-runner" \
--run-untagged \
--locked="false"

如果不清楚docker的命令我们可以不用深究,上述就是注册一个runner的命令,我们需要做的是

  1. 替换掉上面url为自己的地址,域名+端口,或者IP+端口都行

  2. registration-token来自于你的gitlab,进入你的gitlab的设置,就是那个小扳手🔧,里面有个renners选项,页面可以看到你的地址和token密钥,复制token密钥到这里替换掉即可

  3. description描述其实就是备注 不是很重要 自己随便

  4. tag-list是标签,这个是有点用的但是目前我们不需要过分关注,依然自己随便起个名即可。

  5. 成功注册就是如下的状态,我们可以在gitlab上看到他

image.png

此时我们拥有了一个runner了,接下来需要让他工作了,我们如何打通gitlab和docker呢?

编写pipeline

一个构建流程我们称之为pipeline流水线的意思,他可能有多个步骤。

拿我们的前端项目举例,最基础的情况也需以下几步

  1. npm install安装依赖
  2. npm run build打包项目
  3. 将生成的dist文件打包目录部署

这条流水线其实可以编辑非常多的功能,可能包含一些检测,代码覆盖率测试,代码检测,分支部署等等其他工单,这里篇幅较大,我们本文也暂时简要描述。

我们需要在项目根目录创建一个配置文件 .gitlab-ci.yml文件,当git push代码后将会执行这个文件,下面给个基础的例子:

stages:
  - install
  - lint
  - build
  - deploy

install_job:
  stage: install
  script:
    - echo "This is the install job"

lint_job:
  stage: lint
  script:
    - echo "This is the lint job"

build_job:
  stage: build
  tags:
    - default
  only:
    - master
  script:
    -  echo "This is the build job"

deploy_job:
  stage: deploy
  tags:
    - default
  only:
    - master
  script:
    - echo "This is the deploy job"

你可以尝试把这个文件加入到你的项目里,前提是你在gitlab上创建了项目并关联了,然后推送之后,你可以看到项目中的cicd那一列点开后有一条线正在构建中。类似下图

image.png

这个过程呢就是上图中的,有四步,分别是

  1. 下载依赖 install
  2. 检查代码 lint
  3. 打包项目 build
  4. 部署项目 deploy

当然我们并没有真的执行,每一步都只是打印了一句话,这里我只是想让你尝试一下对此有个模糊的概念即可,它的构建工作就是这样做的,

然而,我们今天并不需要在这里进行这些工作,我们在.gitlab-ci.yml中编写的文件都是在gitlab中进行的,而我们需要在docker当中去进行项目部署,所以这些步骤的前三步都可以省略,我们进行直接部署,我们将文件改写为:

image: docker:stable
stages:
  - deploy 

deploy:
  stage: deploy  
   script:
    - echo 'cicd --deploy'
    - docker build -t test:image .
    - if [ $(docker ps -aq --filter name=test-container) ]; then docker rm -f $CONTAINER;fi
    - docker run -d -p 7000:80 --name test-container $IMAGE

改写成上面是什么意思呢,推送代码之后我们会用docker build一个镜像,名称为test:image,同时检测有没有容器名字为test-container的有就删除,然后启动docker容器,这样7000的端口表示暴露的外网端口,80是容器内端口,前端静态项目我们一般都是访问80即可,如果部署成功,我们IP+端口就可以访问项目了,

当然这并没有结束,这里只表示我们在推送完代码之后启动了一个容器,但是Docker启动的过程中我们需要一个类似gitlab-ci.yml的指令文件告诉其启动步骤,

本文不过多讲解docker,我们直接上一个文件即可:

FROM node:14.17.6 as build-stage

WORKDIR /app
COPY package*.json ./
RUN npm install --registry=https://registry.npm.taobao.org

COPY . .
RUN npm run build

FROM nginx:latest
COPY --from=build-stage /app/dist /usr/share/nginx/html

EXPOSE 80

大概介绍下上面流程,当我们通过gitlab-ci文件启动docker容器后,将会走到这里,首先创建了一个工作目录app,然后拷贝了package.json文件,然后按照依赖,然后打包,前面的步骤其实很好理解,因为我们在本地开发拉取一个项目也是这个步骤,后面呢则是将打包的文件放入nginx服务器当中,最后暴露一个80端口。在这里我只介绍流程,告诉你一个基础流程,将此文件放入项目目录中,此时再次推送,如果不出意外,将会项目部署成功,此时访问ip:7000就可以访问项目了,这里的7000是我们在ci文件中启动容器自己指定的端口你可以随意更改,最终我们还可以通过nginx去代理隐藏掉我们的端口号。

至此,我们已经可以成功的部署一个前端项目了,后端项目的部署也是大同小异,本文的部署存在诸多的未处理细节,但本意上我觉得是应该快速先实现一套可以走通的流程再去考虑细节,如果你完全安装本文来做,那你你应该到此是可以实现一个简单的cicd系统了,后续更多的地方需要自己去完善探索,本文更想告诉你的是cicd实现的思想和思路。

总结

CICD的流程在企业开发中作为前端开发你很难接触到全面,想要去学习更趋于自己去实现,并且企业级别的CICD也会结合K8s去做集群部署,本文与其还有较远的路程,当然一遍文章也很难概述得了一套全面的系统,我更推荐你作为个人开发者能自己去实现一遍这样的流程,可能在大公司并没有你施展的机会,但是如果你是相对小一些的企业,或者很小的甚至没有cicd系统流程的公司,你也可以尝试从0开发一整套。在现在的环境中来看,各种各样的平台也拥有了各类自动化部署能力,这一项能力对于个人来说并不是需要,但是对自己的概念流程认知会有很多提升,特别对于爱折腾的个人开发来说,打造这样的一套属于自己的部署系统也会在一定程度被动的激发自己的开发兴趣,是一个不错学习点。

建议

在学习本文想要自己去实现这套流程前,建议先去阅读学习一下docker的一些基础知识,这里推荐这个文档🎉 Docker 简介和安装 - Docker 快速入门

gitlab的知识会相对简单一些,但是对于pepiline流水线编写其实也会有很多的内容,如果你想将系统构建的更为完善,这两部分内容是你优先需要学习的内容。

最后自动化部署有非常多的实现,本文只是其中的一种实现方式,并且是一遍比较细致的快速入门文章,如果你有建议和补充,希望奉献你宝贵的建议。