在快速迭代的软件开发环境中,持续集成(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
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. 阿里云镜像加速器配置。
执行命令(逐行在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)。
docker-compose.yml配置文件如下:(要新建相对应的文件)
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界面上,可以实时查看构建日志和流水线状态。
注意(踩坑点):
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了,所以要加上缓存,如果有镜像就不拉取了)
结论与展望 通过结合Docker、GitLab CI和GitLab Runner,我们成功搭建了一个高效的CI/CD流水线。这个流水线不仅提高了开发效率,降低了错误率,还加速了软件交付周期。未来,我们可以进一步优化流水线配置,如使用Kubernetes集群进行部署、集成监控和告警系统等,以进一步提升CI/CD流程的可靠性和可扩展性。
总之,Docker、GitLab CI和GitLab Runner的组合为现代软件开发团队提供了一个强大的CI/CD解决方案。通过自动化构建、测试和部署过程,我们可以更快地响应市场变化,提供更高质量的软件产品。