ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

GitLab从零到实战:部署、权限、CI/CD与避坑指南

GitLab从零到实战:部署、权限、CI/CD与避坑指南 GitLab这东西说难不难说简单也真不简单。我是从GitHub转过来的刚上手的时候也被它的权限模型、Runner、CI/CD绕得晕头转向。后来在本地服务器上完整搭过几次也帮不少团队做过迁移和落地才算把这套东西彻底玩明白。这篇“骨灰级入门”就是把GitLab从零开始讲清楚包括它到底是干嘛的、怎么在服务器上跑起来、日常怎么用、怎么把CICD流水线跑通以及一堆新手必踩的坑。适合刚接触GitLab、打算在公司搭一套内部代码托管平台的同学也适合一直会用GitHub但搞不懂GitLab为什么那么多人说的读者。1. 为什么是GitLab和GitHub、Gitee到底差在哪先花点时间搞清楚定位。GitLab本质上是一个基于Git的代码托管平台但它的野心早就超出“放代码”这个范畴了。现在你打开一个GitLab实例看到的不只是仓库列表还有Issue跟踪、Wiki、CI/CD流水线、容器镜像仓库、代码质量分析、安全扫描。它是一个完整的DevOps生命周期管理平台。和GitHub相比最大的区别在于GitLab强调“私有化部署”。GitHub虽然有企业和私有仓库但绝大多数场景代码还是托管在别人服务器上。而GitLab可以装到你自己内网的一台机器上代码、流水线、制品全在自己手里这对于很多公司来说是不可替代的优势。Gitee虽然也提供私有化方案但功能成熟度和生态丰富度跟GitLab还是有差距特别是CI/CD这块GitLab Runner的灵活性和可定制性是同类产品里非常能打的。再一个区别是权限模型。GitLab的权限体系比GitHub更细致从实例级到群组级再到项目级一层套一层可以做到非常精细的管控。这在公司场景里很重要比如让研发团队只能看自己组的代码QA只读不能写运维只对某几个项目有权限这些用GitLab都能轻松配出来。所以如果你需要一套能自己掌控、开箱即用、自带CI/CD的代码平台GitLab基本上是首选。2. 部署安装Docker一把梭是最省心的路2.1 环境要求和准备工作先说硬件GitLab确实是个资源大户尤其你如果还要跑CI的话。我自己在2核4G的云服务器上装过光跑GitLab服务本身勉强能转但一旦有Runner同时跑几个Job内存直接报警。建议最低4核8G磁盘至少配50G以上如果要跑Docker镜像构建磁盘再多给点镜像缓存吃起空间来很吓人。系统方面Ubuntu 20.04/22.04、CentOS 7/8、Rocky Linux都行Debian系和RHEL系都有对应的安装方式。如果你用的是国内云服务器记得先把系统源换成国内源不然拉包会非常痛苦。域名方面提前说一句GitLab对外暴露的地址很关键。很多人部署完发现clone地址不对就是因为没在配置里写清external_url。这个后面会专门讲。2.2 Docker Compose安装半小时跑起来我用过Omnibus包直接装也用过Docker部署两种都试过。如果你没有特殊要求我真心推荐Docker Compose方式原因就一个干净。GitLab有大量依赖组件PostgreSQL、Redis、Gitaly这些Omnibus包会在宿主机上装一堆东西后续卸载升级都是事。容器化之后所有组件都在容器里主机非常清爽升级也简单换个镜像版本就行。这是我实际用的一个最小化compose配置你先照这个跑后面再慢慢加东西version: 3.6 services: gitlab: image: gitlab/gitlab-ce:latest container_name: gitlab restart: always hostname: gitlab.example.com environment: GITLAB_OMNIBUS_CONFIG: | external_url http://gitlab.example.com gitlab_rails[time_zone] Asia/Shanghai gitlab_rails[gitlab_default_projects_features_issues] true nginx[enable] true nginx[listen_port] 80 # 下面是邮箱配置可以用测试邮箱先跑通 # gitlab_rails[smtp_enable] true # gitlab_rails[smtp_address] smtp.qq.com # gitlab_rails[smtp_port] 465 # gitlab_rails[smtp_user_name] xxxxqq.com # gitlab_rails[smtp_password] 授权码 # gitlab_rails[smtp_authentication] login # gitlab_rails[smtp_tls] true ports: - 80:80 - 443:443 - 22:22 volumes: - gitlab_config:/etc/gitlab - gitlab_logs:/var/log/gitlab - gitlab_data:/var/opt/gitlab shm_size: 256m volumes: gitlab_config: gitlab_logs: gitlab_data:重点解释几个参数这些坑我都踩过external_url这是GitLab对外展示的基础地址clone代码、网页访问、webhook推送都基于这个URL生成。如果你只填IP后续clone地址就是http://192.168.x.x/group/project.git特别难看。提前定好一个域名填进去后面所有操作都顺。GITLAB_OMNIBUS_CONFIG这是GitLab自带的Omnibus配置入口容器启动时会把这个配置写进/etc/gitlab/gitlab.rb。注意这里写的是ruby语法格式别搞错。22:22SSH端口映射。如果宿主机22端口被占了可以映射成别的端口比如2222:22但要注意这样clone地址会带上端口得在配置里设置gitlab_shell[ssh_port] 2222让GitLab知道怎么拼地址。shm_size这个很多人忽略。GitLab的PostgreSQL对/dev/shm要求较高默认64M在跑备份或者大数据量操作时会报错。我后来设成256m没再出过问题。启动命令很简单docker-compose up -d启动之后第一次访问会比较慢因为容器里要初始化数据库、编译assets慢的话可能要等几分钟。你可以在服务器上观察日志docker logs -f gitlab看到类似gitlab Reconfigured!或者gitlab started successfully的日志再去浏览器访问。2.3 首次登录和初始密码GitLab首次启动会自动生成一个初始root密码存在容器里的/etc/gitlab/initial_root_password文件中。用这个命令查看docker exec -it gitlab cat /etc/gitlab/initial_root_password文件里那个Password:后面的字符串就是初始密码。用root用户名登录后第一件事就是去用户设置里把密码改掉这个初始密码好像24小时后会自动删除。如果你连这个文件都没看到说明容器已经初始化过那就是之前设置过密码或者密码文件被清了只能用gitlab-rails console重置这个后面放进排查章节讲。3. 日常高频操作从创建项目到第一行代码上传3.1 创建一个项目Group和Project的关系在GitLab里项目是代码仓库的基本单元但它通常放在Group里。Group就是你理解的“群组”或“团队”它下面可以挂成员可以建多个Project还可以再套子Group。这个层级结构说白了就是两层权限和管理关系——你把张三加到一个Group里这个Group下所有项目的权限就都给了张三不用挨个项目去加人。所以你在创建项目之前建议先建一个Group。路径是左侧边栏“群组” - “新建群组”。填名字、路径、可见性这几个字段就行。可见性在私有化部署下一般选“Private”保证只有被邀请的人能看到。创建好Group之后在Group里点“新建项目”流程就很顺畅了。GitLab会让你选是创建空白项目、从模板创建还是导入已有项目。初次使用直接选“Create blank project”。3.2 SSH密钥配置一次性搞定以后免密操作这里是新手第一个卡点。用HTTP方式clone代码每次都要输用户名密码非常烦人。配置SSH密钥是实现“一次配置终身免密”的标准方案。先检查本机是否已生成过密钥ls -la ~/.ssh/如果你看到id_rsa和id_rsa.pub这两个文件说明已经生成过可以跳过生成步骤。没看到就执行ssh-keygen -t ed25519 -C 你的邮箱example.com现在新项目推荐用ed25519算法安全性比RSA更好生成速度也快。一直回车使用默认路径和空密码就行。然后查看公钥内容cat ~/.ssh/id_ed25519.pub复制输出的整段内容到GitLab右上角头像 - “偏好设置” - “SSH密钥”粘贴保存。验证是否生效执行ssh -T gitgitlab.example.com如果返回类似Welcome to GitLab, yourname!的提示就说明SSH配置成功了。这个返回信息最有用你一看就知道到底是谁在连接。3.3 把代码推到远程仓库clone和push实战项目建好之后本地把代码推上去就两条路一是clone空白项目到本地再把文件拷进去二是在已有项目里直接加remote。先看clone的完整流程。项目主页点“克隆”会给你两个地址SSH格式通常长这样gitgitlab.example.com:group/project.gitHTTP格式长这样http://gitlab.example.com/group/project.git推荐用SSH方式原因前面说了代码拉取不用输密码git clone gitgitlab.example.com:group/project.git cd project如果你已经有本地文件夹想直接推上去可以这样cd /path/to/your/project git init git remote add origin gitgitlab.example.com:group/project.git git add . git commit -m Initial commit git push -u origin masterpush的时候很多人会碰到分支名问题。GitLab默认分支是master新版也可以设置成main但GitHub旧仓库经常用main。如果本地分支名字和远程不一致push会报错。最简单的处理方式是先查一下本地的分支名git branch如果远程是master分支而本地是main你可以这样git branch -m main master或者干脆指定推送git push -u origin HEAD:master这情况很常见特别是从GitHub项目转过来的同学本地代码还是main习惯推GitLab就直接撞分支名不一致的坑。4. 权限模型与成员管理别让每个人都拥有root权限4.1 GitLab的权限层级很多公司把GitLab搭起来之后发现所有人都能用root登录吓得不行。其实GitLab的权限体系做得很清晰关键你要理解角色。单个项目层面有5种角色Guest只能看Issue看Wiki代码不能读。Reporter可以读代码可以看合并请求适合QA、产品这类需要了解内容的角色。Developer可以写代码可以推送分支可以发起合并请求。Master现在叫Maintainer可以管理项目设置、管理成员、保护分支放开后可以执行部分管理操作。Owner项目的最终所有者权限最大。Group层面的角色和项目类似但作用于整个群组内所有项目。你在Group里把一个人设为Developer那他就能push这个Group下所有项目。实例层面就是管理员那是少数人该有的权限日常开发根本用不到。万一你给了谁root他能改全局配置、看所有项目这个安全风险非常大。我在维护过程中就把管理员账号锁得死死的除了真正管系统的人其他人全部降权。4.2 保护分支和代码评审保护分支是GitLab一个很实用的功能相当于给你的主干分支上一道锁。项目设置 - 仓库 - 保护分支默认情况下master分支是被保护的意味着Developer不能直接push到master只能通过合并请求。这个逻辑跟GitHub的受保护分支类似但GitLab做得更细可以精确控制“谁能直接push”“谁能合并合并请求”“谁能强制推送”。实际团队协作里我建议这样配master/production分支只有Maintainer可以合并Developer只能提Merge Request。develop分支Maintainer和Developer都可以push合并请求放开。feature分支不保护随便玩。配合合并请求审批功能可以设置代码需要1到2个人Review通过才能合并这样小组协作质量就有保障了。4.3 项目可见性设置私有化部署环境下的可见性也要注意。新建项目时GitLab默认可能让你选Private、Internal还是Public如果选Public那这个项目的代码会被实例上所有人看到包括所有能登录系统的人。如果你想让代码只有项目成员能看记得选Private。这个坑我碰到过有一次团队的人新建了一个项目系统自动默认成Public过了半天才发现代码能被全公司的人看到虽然不涉及外网泄露但内部信息的范围控制就失控了。所以公司内如果没有特殊需求默认就让大家建Private项目设置里甚至可以改掉默认值。5. 打通CI/CDGitLab Runner和.gitlab-ci.yml的配合5.1 Runner是什么为什么要单独装GitLab的CI/CD是整个平台我认为最有价值的部分代码push上去之后自动测试、构建镜像、部署到服务器一套流程全部自动化。能做到这套事情靠的是两个核心Runner和.gitlab-ci.yml文件。Runner可以理解成一堆“打工的机器”它们从GitLab服务器领取任务执行构建脚本把结果上报回去。GitLab服务器本身不干活它只负责派活和收结果。Runner可以装在同一台机器上也可以单独搞几台专门的构建机还可以用Kubernetes动态弹出一堆临时Runner这个思路非常像共享单车的调度中心调度中心不骑单车它只派单。Runner安装很简单在要用作构建的机器上下载gitlab-runner的包然后注册到GitLab实例sudo gitlab-runner register注册过程会让你填GitLab实例地址和注册tokentoken可以从项目设置 - CI/CD - Runner里找到。填完之后会让你选executor新手最推荐用docker类型因为每个Job跑在一个干净的Docker容器里环境互相隔离不怕污染sudo gitlab-runner register \ --url http://gitlab.example.com \ --token 你的注册token \ --executor docker \ --docker-image docker:20.10.16 \ --docker-volumes /var/run/docker.sock:/var/run/docker.sock这段命令里最后一行的/var/run/docker.sock挂载是关键。如果你的流水线要做Docker镜像构建Runner容器里需要能调用宿主机的Docker守护进程俗称Docker-in-Docker或者Docker socket方式。我建议用sock方式简单高效比真正的DinD更省资源缺点是构建环境里能直接操作宿主机Docker需要谨慎使用。5.2 .gitlab-ci.yml初体验三步构建加一个镜像这个文件放在项目根目录名字必须叫.gitlab-ci.ymlGitLab每次推送都会检测到这个文件然后按里面的流水线定义跑任务。先看一个最简单的例子功能是项目一旦有push到master的代码自动构建一个Docker镜像并推到GitLab的Container Registrystages: - build - package variables: IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA before_script: - echo pipeline from $CI_PROJECT_NAME build: stage: build script: - echo 开始编译代码 - echo 这里放编译命令比如 mvn clean package 或者 npm run build package: stage: package script: - docker build -t $IMAGE_NAME . - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker push $IMAGE_NAME这个文件里涉及几个GitLab内置变量我解释一下$CI_REGISTRY_IMAGE项目对应的镜像仓库地址GitLab自带一个Docker Registry每个项目都有专属的镜像路径在“项目设置 - 通用 - 可见性、项目功能权限”里能看到。$CI_COMMIT_SHORT_SHA当前提交的简短哈希值用来给镜像打标签保证每个提交产生的镜像都是唯一的。$CI_REGISTRY_USER和$CI_REGISTRY_PASSWORDGitLab自动注入的Registry账号密码用来登录镜像仓库。stages定义了两个阶段build和package。同一阶段的Job可以并行执行不同阶段按顺序执行。如果你前面阶段失败了后面阶段就不会跑这个特性在部署场景特别有用——编译都没通过肯定不会去部署。5.3 多环境自动化部署从测试环境到生产环境上面那个例子只是构建镜像如果要部署到服务器需要再增加部署阶段。这是群里问得最多的一块我写一个可以实际照抄的多环境部署模板stages: - build - package - deploy-test - deploy-prod variables: IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA TEST_SERVER: 192.168.1.100 PROD_SERVER: 192.168.1.200 TEST_DIR: /opt/app/demo PROD_DIR: /opt/app/demo before_script: - echo pipeline from $CI_PROJECT_NAME, branch $CI_COMMIT_BRANCH build: stage: build script: - echo 编译代码并跑测试 only: - branches package: stage: package script: - docker build -t $IMAGE_NAME . - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker push $IMAGE_NAME only: - branches deploy-test: stage: deploy-test script: - echo 部署到测试服务器 - sshpass -p $TEST_SERVER_PASSWORD ssh -o StrictHostKeyCheckingno root$TEST_SERVER docker pull $IMAGE_NAME docker stop demo-app || true docker rm demo-app || true docker run -d --name demo-app -p 8080:80 $IMAGE_NAME only: - develop - master deploy-prod: stage: deploy-prod script: - echo 部署到生产服务器 - sshpass -p $PROD_SERVER_PASSWORD ssh -o StrictHostKeyCheckingno root$PROD_SERVER docker pull $IMAGE_NAME docker stop demo-app || true docker rm demo-app || true docker run -d --name demo-app -p 8080:80 $IMAGE_NAME only: - master when: manual这里要说的关键点第一个是only条件。它控制Job在什么情况下会被执行。上面配置里deploy-test在push到develop或master分支时自动执行deploy-prod只对master生效还加了when: manual表示需要人工点按钮才会触发这是生产环境部署的常见做法防止每次代码合并都意外触发生产发布。第二个是SSH登录。上面用sshpass方式直连服务器适合入门但在生产环境更安全的做法是配置SSH密钥把Runner机器的公钥加到服务器的authorized_keys里然后直接ssh执行远程命令不传明文密码。密码这个方式在CI日志里很容易泄露一定注意。5.4 没有.gitlab-ci.yml为什么也触发了Runner这个热搜词很典型很多人说“我的项目里根本没写.gitlab-ci.yml为什么Runner还是被触发了”这里有个容易混淆的地方Runner“被注册”之后会出现两种情况一种是项目里没有.gitlab-ci.ymlGitLab扫描代码库发现没有CI配置文件那这个项目不会有pipeline产生Runner自然也不会跑这个项目。但如果你在Runner配置的tag、描述里设置成能处理该类项目并且项目的CI/CD配置里开启了“指定Runner”那GitLab方面仍可能因为某些操作触发pipeline校验。还有一种可能是你的项目是通过模板创建的模板里自带.gitlab-ci.yml你没注意到。排查方法很简单到“项目 - CI/CD - 流水线”页面看有无历史pipeline记录再检查项目根目录是否确实没有.gitlab-ci.yml。如果确认没有那说明Runner的runner配置可能有误或项目是从模板创建的。6. 常见问题与排查技巧实录6.1 登录失败Check API token or GitLab version这是一个很经典报错通常出现在IDE插件、API工具或者Jenkins连接GitLab时login failed. check api token or gitlab version. log in via git if the version is old...这个报错有两层原因第一API token确实无效你复制粘贴时可能带了空格或者选错了token类型。第二你用的API token权限不够有些操作需要读API、写API、写仓库等权限而token只开了read权限。排查顺序是先在浏览器里确认token是否有效然后看token权限范围最后确认GitLab版本和工具兼容性。GitLab API的版本演进很快老版本的一些API路径和参数在新版本里已经废弃如果你的工具和GitLab版本差得太远确实会报错。6.2 Clone地址怎么变成机器ID了这个也是高频问题。部署在Docker里的GitLab如果不设置external_url或者设置了hostname但没配置对应的clone地址GitLab会基于容器ID或内部主机名生成clone URL。我第一次部署时没配external_urlclone地址长这样http://a1b2c3d4e5f6/group/project.git一看就不是给人用的。解决方法是设置正确的external_url然后执行gitlab-ctl reconfigure让配置生效。Docker部署的改法是用docker exec -it gitlab gitlab-ctl reconfigure。如果你已经绑定了域名但clone地址还是IP或者机器名多半是nginx配置或者external_url配置不完整。建议把external_url完整写成http://gitlab.example.com确保能解析到这台机器上。6.3 本地Git同时配置GitHub和公司GitLab的SSH这问题在热搜里也有很多人电脑上既有GitHub账号又是公司项目的GitLab账号两个SSH密钥混在一起经常连错。解决方案是给不同的host配置不同的SSH密钥。假设你的公司GitLab是gitlab.example.com生成第二个密钥ssh-keygen -t ed25519 -C 你的公司邮箱 -f ~/.ssh/id_ed25519_gitlab编辑~/.ssh/config文件没有就新建# GitHub Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519 # 公司GitLab Host gitlab.example.com HostName gitlab.example.com User git IdentityFile ~/.ssh/id_ed25519_gitlab这样你在克隆公司GitLab仓库时系统会自动使用对应的私钥文件和GitHub互不干扰。记得把新生成的id_ed25519_gitlab.pub公钥加到公司GitLab上的SSH密钥列表里。6.4 GitLab高危漏洞怎么修GitLab因为功能多、组件复杂确实会爆出一些安全漏洞而且高危的不少。处理思路只有一个跟着官方通告升级版本别拖延。我见过不少团队GitLab一装就是一年期间官方都发了七八个安全版本了他们还跑着最初那个版本。这真的不行因为很多RCE漏洞就藏在这种长期不更新的系统里。修复建议是先明确当前版本然后查看官方安全公告找到包含该漏洞修复的第一个版本跳级升级过去。升级前一定要先备份尤其是数据库。GitLab升级有时候需要按版本号逐级升跳太多会出兼容性问题这一点官方文档里都写了照着做就行。Docker部署的话升级比较简单拉新镜像替换即可但执行前务必用快照或者备份脚本把整个gitlab目录备份一遍。7. 一个小技巧和一点个人心得最后分享两个小经验。第一给GitLab配上邮件通知。不配邮件很多协作流程根本跑不起来——别人提了Merge Request你根本不知道。邮箱配置在Omnibus配置里我上面compose里留了注释的smtp配置就是QQ邮箱的。现在阿里云、腾讯云的企业邮箱也都能配照着SMTP参数填进去就行。配置完成后一定要用测试功能发一封测试邮件确认别等团队用几天了才发现邮件全进了垃圾箱。第二备份这件事真的不能省。GitLab里的代码、Issue、CI日志、镜像丢了是很难重建的。我建议至少每天凌晨做一个备份任务直接把备份文件迁移到异地存储。GItLab官方有现成的备份命令docker exec -t gitlab gitlab-backup create配合crontab定时跑就行。等真碰到硬盘坏掉或者误删项目的时候你会发现这个备份是你花过最值的几分钟。根据我自己搭过几套GitLab的经验入门最关键的一步其实就是把环境跑通之后的上手路径反而是顺其自然的。你先把代码推上去再玩玩Merge Request和权限配置然后试着跑通一条最简单的CI任务整个GitLab的面貌就一下子亮了。别的那些高级功能遇到具体问题再查都是在帮自己加深理解。
返回列表