Docker、Nginx、GitLab CI 与 GitLab Runner:构建高效CI/CD流水线的实践

671 阅读14分钟

在快速迭代的软件开发环境中,持续集成(CI)和持续部署(CD)已成为提升开发效率、保障软件质量的关键实践。本文将详细介绍如何使用Docker、GitLab CI以及GitLab Runner来搭建一个高效的CI/CD流水线,实现应用程序的自动化构建、测试和部署。

Docker:容器化技术的魅力 Docker作为一种轻量级的容器化技术,为应用程序及其依赖项提供了一个独立的运行环境。它确保了应用在不同环境下的一致性和可移植性,极大简化了部署过程。通过Docker,我们可以快速启动新的开发、测试或生产环境,从而加速软件交付周期。

GitLab CI:持续集成的核心 GitLab CI是GitLab内置的持续集成和持续交付平台。它允许开发团队在代码提交或合并请求时自动触发构建、测试和部署任务。GitLab CI的流水线(pipeline)由多个阶段(stage)组成,每个阶段可以包含多个任务(job)。这些任务在GitLab Runner中执行,从而实现了CI/CD流程的自动化。

GitLab Runner:CI/CD任务的执行者 GitLab Runner是GitLab CI的执行器,负责运行流水线中定义的任务。它可以注册为共享Runner(为所有项目服务)或特定Runner(为指定项目服务)。Runner可以运行在Docker容器、Shell脚本或Kubernetes集群等环境中,提供了高度的灵活性和可扩展性。

前置准备

服务器一台(CentOS 7.9 64位)
nodejs
npm

实现步骤

安装和配置Docker

首先,需要在服务器上安装Docker。安装完成后,拉取所需的Docker镜像,如GitLab镜像,为GitLab CI/CD流水线提供必要的环境。 安装和配置Docker的具体步骤可能因操作系统而异。以下Linux系统上安装和配置Docker的详细步骤:

使用Docker之前,需要先把Docker安装好。 如果已经安装过其他版本的Docker,先把它们及依赖卸载。如果没有安装过,则不用执行下面命令。

sudo yum remove docker \
              docker-client \
              docker-client-latest \
              docker-common \
              docker-latest \
              docker-latest-logrotate \
              docker-logrotate \
              docker-engine

安装Docker的依赖库。

安装需要依赖库。yum-utils 提供了 yum-config-manager ,并且 device mapper 存储驱动程序需要 device-mapper-persistent-data 和 lvm2。 CentOS内并没有Docker相关的软件包,如果不执行下面命令,使用 yum安装Docker时,则找不到软件包。

yum install -y yum-utils device-mapper-persistent-data lvm2

添加Docker CE的软件源信息

这个是官方软件源,比较慢。

sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

这个是阿里云软件源,国内的话推荐使用这个。

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

安装Docker CE。

注意:这里会自动安装相关的docker-ce、containerd.io、docker-ce-cli 和 docker-ce-rootless-extras 依赖,如果有询问直接 y 即可

sudo yum install docker-ce

启动Docker服务。

  // 设置开机自启
  sudo systemctl enable docker 

  // 启动docker
  sudo systemctl start docker 

通过执行测试映像验证是否安装正确

  sudo docker run hello-world

image-1.png

Dcoker相关命令。

sudo systemctl restart docker  // 重启Docker
sudo docker version // 查看版本
sudo docker info    // 查看相关信息
sudo docker iamges  // 查看安装镜像

Docker安装docker-compose。

docker-compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。下载docker-compose:

1.命令行进行下载

curl -L https://get.daocloud.io/docker/compose/releases/download/v2.4.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

将可执行权限应用于二进制文件:安装完成后提升权限

sudo chmod +x /usr/local/bin/docker-compose

检查是否安装成功:

docker-compose -v

如果安装失败,此时需要切换到官方github链接去安装(较慢)

sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Docker安装Nginx服务

docker pull nginx:latest

如果出现超时或者拉取不下来的情况。(本人遇到)

方法1. 阿里云镜像加速器配置。

image-2.png

执行命令(逐行在linux上执行命令行)

 sudo mkdir -p /etc/docker
 cd /etc/docker
 vim daemon.json

 {
   "registry-mirrors": ["Your own mirror address"]
 }

 sudo systemctl daemon-reload
 sudo systemctl restart docker

方法2. 阿里云镜像加速器配置。

需要借助第三方网站来拉取镜像,人家公司的服务器会自动连国外的服务器来帮你拉取镜像。(本人亲测)

一旦镜像下载完毕,你可以使用docker tag命令为其赋予一个新的名字。例如,如果你想把当前的hub.c.163.com/library/nginx镜像改名为my-custom-nginx

 docker tag hub.c.163.com/library/nginx my-custom-nginx

创建docker的相关目录,方便维护

   mkdir /docker           
   mkdir /docker/compose    
   mkdir /docker/nginx      
   mkdir /docker/nginx/conf 
   mkdir /docker/html       

/docker/compose是放置docker-compose,/nginx/conf是放置nginx.conf配置文件,html是放置代码文件(dist)。

image copy 2.png

docker-compose.yml配置文件如下:(要新建相对应的文件)

image copy.png

version: '3.8'
  services:
    docker_nginx_dev:
    restart: always
    image: nginx
    container_name: nginx
    ports:
        - '8001:8001'
    volumes:
        - '/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf'
        - '/docker/html:/usr/share/nginx/html'
        - '/docker/nginx/logs:/var/log/nginx'

它描述了一个多容器Docker应用程序的服务。,只定义了一个服务:docker_nginx_dev。下面是对该配置文件中各个部分的解释:

version:'3.8'
这指定了Docker Compose文件格式的版本。版本3.8引入了一些新的功能和特性,比如对服务配置的更多控制和更好的兼容性。
services:
这是定义服务列表的顶级键。在Docker Compose中,你可以定义多个服务,每个服务都会运行一个容器。
docker_nginx_dev:
这是服务的名称。在这个例子中,服务名称是docker_nginx_dev。你可以使用这个名称来引用服务,比如在运行docker-compose命令时。
restart: always
这指定了容器的重启策略。always意味着容器总是会在退出后重新启动,无论退出状态码是什么。这对于确保服务始终可用非常有用。
image: nginx
这指定了容器使用的镜像。在这个例子中,它使用官方的nginx镜像。Docker Compose会从Docker Hub(除非指定了其他仓库)拉取这个镜像(如果本地没有的话)。
container_name: nginx
这为容器指定了一个名称。在这个例子中,容器被命名为nginx。注意,如果你在同一Docker网络中运行多个相同镜像的容器,为每个容器指定一个唯一的名称是很重要的。
ports:- '8001:8001'
这定义了端口映射。在这个例子中,它将容器内的8001端口映射到宿主机的8001端口上。这意味着你可以通过访问宿主机的8001端口来访问容器内运行的服务(在这个例子中是Nginx)。
volumes:
- '/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf'
- '/docker/html:/usr/share/nginx/html'
- '/docker/nginx/logs:/var/log/nginx'
这定义了卷映射。卷允许你将宿主机的目录或文件映射到容器内的目录或文件上。在这个例子中,有三个卷映射:
第一个将宿主机的/docker/nginx/conf/nginx.conf文件映射到容器内的/etc/nginx/nginx.conf文件上,允许你自定义Nginx的配置。
第二个将宿主机的/docker/html目录映射到容器内的/usr/share/nginx/html目录上,这是Nginx默认的静态文件目录。
第三个将宿主机的/docker/nginx/logs目录映射到容器内的/var/log/nginx目录上,允许你访问Nginx的日志文件。
这个Docker Compose文件定义了一个名为docker_nginx_dev的服务,它运行官方的Nginx镜像,并将特定的文件和目录从宿主机映射到容器内,同时还配置了端口映射和重启策略。

nginx.conf 例:

/docker/nginx/conf/nginx.conf 相关配置

   user  nginx;
   worker_processes  1;

   error_log  /var/log/nginx/error.log warn;
   pid        /var/run/nginx.pid;
   events {
       worker_connections  1024;
  }

  http {
      include       /etc/nginx/mime.types;
      default_type  application/octet-stream;
      log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for"';
      access_log  /var/log/nginx/access.log  main;
      sendfile        on;
      #tcp_nopush     on;
      keepalive_timeout  65;
      gzip  on;
      #dev环境
    server {
           #监听的端口
          listen  8001;
     server_name  localhost;
       #设置日志
 #   access_log  logs/dev.access.log  main;
    location ~ .*\.(htm|html|gif|jpg|jpeg|png|ico|rar|css|js|zip|txt|flv|swf|doc|ppt|xls|pdf|json|ico|htc)$ {
       root  /usr/share/nginx/html/dist;
        # 存放文件的地址
        try_files $uri $uri/ @router; 
        index  index.html index.htm;
    }

    location ~ /api/ {
    #   proxy_pass http://127.0.0.1:8787;
    #   autoindex on;
    #   if ( !-e $request_filename ) {
      proxy_pass  http://39.105.117.225;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    #  }
    }
    location / {
        #linux下HTML文件夹,就是你的前端项目文件夹
         root   html/dist;
         index  index.html index.htm;
        #输入网址(server_name:port)后,默认的访问页面
        # index  index.html;
        try_files $uri $uri/ /index.html;
       }
    #    error_page 404 https://www.baidu.com;
  }
}

注意(这里有一个踩坑点)
如果访问自己服务器后端接口,结果一直出现502 GateWay的报错信息,最终找了半天的问题,发现是ip地址的问题!
proxy_pass http://127.0.0.1:8787; 地址不能写localhost或者127.0.0.1,否则nginx会报这个错误。

因为我的项目是在docker容器中运行的,所以会牵涉到一个宿主机和容器的映射关系,这里就要说一下docker的实现原理,服务在docker容器中会有一个单独的虚拟空间进行运行(可以理解为每一个容器就类似于一个单独的虚拟机,ip和端口都是独立的,而且容器只能内网访问,外网是无法直接访问容器的),那么之所以我们访问宿主机的ip和端口,就是因为在启动docker镜像时,我们设置了宿主机和容器的端口映射,所以需要写真实的 ip 和端口 proxy_pass http://39.105.117.225;

环境启动
进入到 docker-compose 同级目录下运行 docker-compose

  cd /docker/compose

执行 docker-compose up -d 去运行 docker-compose

  docker-compose up -d 

查看容器运行状态

  docker ps -a

分别有了相对应的端口证明运行成功
注意:一定要开启安全组相对应端口(),以及如果改动了nginx配置文件记得要执行 docker restart nginx 进行重启
验证nginx环境
在对应目录/docker/html/dist 新建一个index.html
输入 http://服务器ip地址/ 如果页面正常打开代表nginx配置成功

安装和配置GitLab

GitLab CE(Community Edition)是一个开源的代码托管平台,支持Git仓库管理、CI/CD、问题跟踪等功能。以下是在不同环境下安装和配置GitLab CE的具体步骤:

1、使用Docker安装和配置GitLab CE 安装Docker 如果尚未安装Docker,请按照操作系统的官方文档进行安装。

拉取GitLab CE镜像 打开终端或命令提示符,输入以下命令来拉取GitLab CE的Docker镜像:

  bash
  docker pull gitlab/gitlab-ce:latest

或者指定特定版本:

  bash
  docker pull gitlab/gitlab-ce:<版本号>

docker-compose.yml 内添加

 web:
   hostname: 你的主机IP地址
   image: 'gitlab/gitlab-ce:latest'
   restart: always
   ports:
     - '3389:3389' # 注意宿主机和容器内部的端口要一致,不一致需要配置 nginx['listen_port'],否则external_url无法访问
     - '29037:22'
  volumes:
     - './data/config:/etc/gitlab'
     - './data/logs:/var/log/gitlab'
     - './data/data:/var/opt/gitlab'
   environment:
     GITLAB_OMNIBUS_CONFIG: |
       external_url 'http://你的主机IP地址:端口' # 设置外部访问URL
       nginx['listen_port'] = 3389 # 
       nginx['listen_https'] = false
 
  

运行

  docker-compose.yml up -d

查看日志

  docker-compose logs -f

查看状态

  docker-compose.yml ps -a 

访问和配置GitLab CE 打开浏览器,输入http://<你的主机IP地址>(或https://<你的主机IP地址>,如果启用了HTTPS)来访问GitLab CE。首次访问时,需要设置管理员密码。 容器起来之后,默认用户是root,要登录web界面需要先进入容器的这个文件获取密码:

  docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

如果需要进一步配置GitLab CE,可以编辑映射到主机上的配置文件/srv/gitlab/config/gitlab.rb。例如,可以更改external_url来设置GitLab的外部访问地址,或者配置SMTP邮件发送等。修改配置文件后,需要重启GitLab CE容器以使配置生效:

bash
docker restart gitlab

进入自己的gitlab后 修改初始密码 创建项目 克隆项目到本地(推荐用http拉取) 创建ssh密钥,等步骤不做过多阐述

安装和配置GitLab Runner

接下来,安装GitLab Runner,并注册到GitLab CI中。注册时,需要提供GitLab的URL、注册令牌、Runner描述等信息。Runner可以配置为使用Docker作为执行器,以便在独立的容器中运行每个任务。

安装GitLab Runner镜像 接下来,从Docker Hub上拉取GitLab Runner的镜像。可以使用特定的版本号,也可以拉取最新版本:

  bash
  docker pull gitlab/gitlab-runner:latest  # 拉取最新版本

或者

  docker pull gitlab/gitlab-runner:v<具体版本号>  # 拉取特定版本

docker-compose.yml 内添加以下配置

   gitlab-runner:
    image: 'docker.io/gitlab/gitlab-runner'
    container_name: gitlab-runner
    restart: always
    volumes:
      - '/opt/store/gitlab-runner:/etc/gitlab-runner'
      - '/var/run/docker.sock:/var/run/docker.sock'

然后进入gitlab-runner容器,为我们的项目注册runner

// 进入runner容器
   docker exec -it [runner容器ID] /bin/bash
// 执行注册命令
   gitlab-runner register

按照提示输入GitLab实例的URL、Registration Token、Runner的描述、标签列表以及执行器类型等信息。例如:

 bash
 Enter the GitLab instance URL (for example, https://gitlab.com/):
 http://<你的GitLab实例URL>   //  点击左侧菜单中的 `Settings` -> `CI / CD`。

 Enter the registration token:
 <你的Registration Token>  //  点击左侧菜单中的 `Settings` -> `CI / CD`。

 Enter a description for the runner:
 my-docker-runner

 Enter tags for the runner (comma-separated):
 docker,build,deploy

 Enter the executor:
 docker

 Enter the default Docker image (for example, ruby:2.6):
 alpine:latest

完成注册后,GitLab Runner将连接到GitLab实例,并等待接收作业。

验证Runner安装
你可以通过以下命令来验证Runner是否正确安装并运行: 如果出现注册的Runner未连接的情况 可以进入gitlab-runner容器内删除/etc/gitlab-runner/config.toml重新注册

   docker exec -it [runner容器ID] /bin/bash
   cd /etc/gitlab-runner/
   rm -f config.toml

如果Runner已正确安装并运行,你应该能够在GitLab项目的CI/CD设置中看到新注册的Runner。

   bash
   docker logs gitlab-runner  # 查看GitLab Runner容器的日志

配置.gitlab-ci.yml文件

在项目根目录下创建.gitlab-ci.yml文件,该文件定义了CI/CD流水线的配置。在文件中,指定使用的Docker镜像、定义流水线阶段(如build、test、deploy)以及每个阶段的任务。例如,在build阶段,可以构建Docker镜像;在test阶段,可以运行单元测试;在deploy阶段,可以将应用程序部署到生产环境。

  image: docker:stable
     stages:
      - deploy-main
  cache: # 缓存
  paths:
    - node_modules/

  deploy-job:
    image: node:latest
    stage: deploy-main
  tags:
     - build
  script:

      #- /bin/sh -c "echo tet"
      - npm config set registry https://registry.npm.taobao.org
      - npm install
      - npm run build
      - ls -ld ${CI_PROJECT_DIR}/dist/*
      - cp -rfv ${CI_PROJECT_DIR}/dist /usr/share/nginx/html/

      - echo "构建并发布到服务器完成"


    when: on_success

  only:
     - main

提交代码并触发CI/CD

将代码提交到GitLab仓库后,GitLab CI会自动检测到更改并触发相应的CI/CD流水线。GitLab Runner会拉取最新的代码,根据.gitlab-ci.yml文件中的配置执行相应的任务。在GitLab界面上,可以实时查看构建日志和流水线状态。

image.png 注意(踩坑点)
gitLab为了安全,不支持在.gitlab-ci.yml中直接使用volumes(卷挂载),但可以在gitLabrunner配置文件中配置加载卷,与宿主机进行文件交互。位置在/etc/gitlab-runner/config.toml,修改完了要记得重启。

   [[runners]]
     ...
   [runners.custom_build_dir]
   [runners.docker]
     tls_verify = false
    # 在这里进行目录挂载
    volumes = ["/cache", "宿主机目录:容器内目录"]
    privileged = true(PS: 这个设置允许容器以特权模式运行。特权模式给予容器几乎与主机相同的权限,包括访问所有设备。这对于运行需要更高权限的任务(如 Docker-in-Docker)是必要的。警告:特权模式可能带来安全风险,应谨慎使用。)
    pull_policy = ["if-not-present", "always"](PS: 现在普通环境不允许访问docker了,所以要加上缓存,如果有镜像就不拉取了)

image-6.png

结论与展望 通过结合Docker、GitLab CI和GitLab Runner,我们成功搭建了一个高效的CI/CD流水线。这个流水线不仅提高了开发效率,降低了错误率,还加速了软件交付周期。未来,我们可以进一步优化流水线配置,如使用Kubernetes集群进行部署、集成监控和告警系统等,以进一步提升CI/CD流程的可靠性和可扩展性。

总之,Docker、GitLab CI和GitLab Runner的组合为现代软件开发团队提供了一个强大的CI/CD解决方案。通过自动化构建、测试和部署过程,我们可以更快地响应市场变化,提供更高质量的软件产品。