Golang從手工編譯到CI/CD自動化部署
一、DevOps是什么
DevOps = Development(開發) + Operations(運維)。讓開發人員(Dev)和運維人員(Ops)能夠高效協作,通過自動化手段讓軟件更快、更穩定地交付上線。
|
階段 |
沒有 DevOps |
有 DevOps 后 |
|
提交代碼 |
每人自己存 |
統一放到 GitLab |
|
測試 |
測試員手動跑 |
Jenkins 自動跑測試 |
|
部署 |
運維手動 SSH 部署 |
自動構建 Docker 鏡像并推到服務器 |
|
出錯排查 |
日志分散難查 |
統一監控+日志系統(Grafana+ELK) |
|
上線周期 |
幾天甚至一周 |
幾小時甚至幾十分鐘 |
二、CI/CD
(一)概念
1、持續集成:開發團隊中每個人完成一部分代碼后,會頻繁地把自己地改動合并到主分支。每次提交都會觸發一系列流程:拉取代碼、編譯構建、執行單元測試、代碼質量檢查等。如果流程通過,說明當前版本是穩定可運行的,如果失敗,系統會立即反饋,方便開發者快速修復。
2、持續交付: 當代碼通過持續集成地構建和測試后,持續交付會讓系統自動生成可發布的版本包,并自動部署到測試環境、預發布環境中,確保一旦業務方或管理層決定上線,只需要一鍵發布即可。
3、持續部署【慎重!!】:當 CI/CD 流水線跑完所有驗證后(構建、測試、靜態分析、部署到測試環境、驗證通過),系統會自動執行“部署生產”的 Pipeline 階段。
- 打包鏡像:把代碼+運行環境+依賴庫打包成Docker鏡像
- 把鏡像上傳到生產倉庫。
- 假如我的線上服務運行在K8s上,持續部署系統會告訴集群用新版本。(該過程中K8s會一邊啟動新容器、一邊逐步關閉舊容器,確保網站整個過程不宕機)。
- 驗證健康檢查:K8s檢測新容器是否能成功啟動,接口是否正確返回200
- 灰度發布:新版本只在10%的用戶上生效,確認沒問題再逐步擴大。
- 藍綠發布:兩套環境同時存在,切換流程時無中斷。
- 若健康檢查失敗,系統會自動退回舊版本鏡像。
(二)應用部署發展過程
- 開發人員自行上傳代碼:早期沒有專業運維人員,運維工作由開發兼職完成,很容易出錯,也是最原始的方式。
- 開發人員將代碼先發給運維,每次項目發布都由運維人員一步一步手動實現,效率底下且容易出錯。
- 由運維人員編寫Shell、Python等腳本或利用自動化運維工具,如Ansible等實現半自動化應用部署,效率很高,但對技術的專業性有較高要求。
- 通過Web等GUI界面實現一鍵自動化部署。可以通過開源或自研的運維平臺實現方便的應用部署,操作容易,但需要提前構建運維平臺。
(三)CICD流程
在 Golang項目開發中,單測、靜態代碼分析是CI/CD的核心環節,而CI/CD最終服務于部署,四者通過Pipeline形成一個自動化閉環。
1、靜態代碼分析
- 在代碼提交后,執行測試前,通過工具自動檢查(如golint等)代碼規范性和潛在風險。
- 靜態分析是CI的前置步驟,若分析失敗,CI流程會直接終止,不進入測試階段。
- Golang實踐:通過golangci-lint run命令集成到CI工具。
2、單測
- 通過自動化測試用例驗證代碼邏輯是否符合預期,確保新代碼不會破壞既有功能。
- 單測是CI流程的核心驗證環節,需在靜態代碼分析通過后執行。若單測失敗(如測試用例斷言不通過、覆蓋率不達標),則CI流程終止,代碼無法進入構建階段。
- Golang實踐:用go test ./... -cover執行全量單測并生成覆蓋率報告。通過testify等庫編寫斷言。結合race檢測排查并發場景下的競態條件。
3、CI/CD:
- CI:將代碼提交->靜態分析->單測->構建串聯為自動化流程。繼續上面的,如果單測通過后,會構建Golang項目(go build)生成二進制文件或Docker鏡像。
- CD:將CI構建的產物(如Docker鏡像)自動部署到目標環境。
- 開發環境:每次主分支代碼合并后自動部署,供開發團隊測試。
- 生成環境:通過手動審批后部署(持續交付)或全自動部署(持續部署),如使用kubectl將Docker鏡像部署到K8S集群。
Pipeline是將上述環節按順序、有條件串聯起來的自動化腳本,定義了“從代碼提交到部署”的完整路徑。以下是典型Pipeline流程:
# GitHub Actions配置文件示例(.github/workflows/ci-cd.yml)
name: Golang CI/CD Pipeline
on: [push, pull_request] # 觸發條件:代碼推送或PR提交
jobs:
code-check: # 任務1:靜態代碼分析
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with: { go-version: '1.21' }
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3 # 執行靜態分析
unit-test: # 任務2:單元測試(依賴code-check成功)
needs: code-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
- name: Run unit tests
run: go test ./... -coverprofile=coverage.txt # 執行單測并生成覆蓋率報告
build-deploy: # 任務3:構建與部署(依賴unit-test成功)
needs: unit-test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build binary
run: go build -o app main.go # 構建Golang二進制文件
- name: Deploy to server
if: github.ref == 'refs/heads/main' # 僅主分支觸發部署
uses: appleboy/scp-action@master # 將二進制文件推送到生產服務器
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
source: "app"
target: "/opt/golang-app/"
三、 部署Gitlab
準備五個機器
開發機:10.0.0.8
gitlab:10.0.0.100
Jenkins:10.0.0.101
Test1:10.0.0.102
Test2:10.0.0.103
- 在對應的機器上安裝gitlab
- 把寫好的代碼上傳到gitlab上。
- 把提前打包好的代碼壓縮包上傳到開發機。
- yum -y install golang【rocky】:安裝go編譯環境
- apt install golang【ubuntu】
- go build編譯成二進制文件
- ./ginweb:把二進制文件跑起來
- 新建一個群組->在群組里建一個新項目
- 安裝git命令
- 按那個新建的項目下面的命令去執行
- 在開發機上做一個從IP到域名的映射操作,并且同步到其他機器上
- git init:本地只有一個裸倉庫,不知道遠程在哪里
- git remote add origin http://gitlab.wang.org/magedu/ginweb.git:Git會在我的項目配置文件.git/config增加一段內容,意思是本地倉庫有一個叫origin的遠程倉庫,它在Gitlab上的地址是xxxx。這樣本地就和遠程倉庫建立了關聯。
- git add .:加入到緩存區
- git commit -m v1.0
- git branch:查看分支
- git push origin master
- 去gitlab.wang.org刷新就能看到ginweb的代碼。
至此我們完成了從開發把代碼傳到了gitlab上。
四、部署Jenkins
兩大核心組成部分:插件和Pipeline
(一)基于Shell實現簡單代碼部署
- 【Jenkins機器】要先安裝Java,再安裝Jenkins(用腳本安裝)
- 【Jenkins網站】登陸進來之后要修改密碼
- 【Jenkins網站】修改安裝插件的地址為國內的鏡像網站
- 【Jenkins網站】安裝一個gitlab的插件,與gitlab關聯起來
- 【gitlab機器】在Jenkins中的權限改為root;生成密鑰ssh -keygen-->cat .ssh/id_rsa.pub找到公鑰信息。
- 【gitlab網站】SSH密鑰復制上面的
- 【Jenkins網站】把gitlab倉庫的SSH地址復制到Jenkins網站中正在進行的項目創建的Repository URL中。然后還要創建憑證:Manage Jenkins->Manage Credentials->創建全局憑證。在Jenkins機器中輸入cat .ssh/id_rsa查看私鑰信息,并且輸入到創建全局憑證這里。
- 【Jenkins網站】點擊Build Now,Jenkins會從gitlab拉取代碼到服務器上,cd /var/lib/jenkins下多了一個目錄workspace/ginweb,這個就是最初的代碼。
- 【Jenkins機器】安裝go環境【腳本】-->go build這個項目。
- 【Jenkins機器】把代碼拷貝到兩臺生產機上。在ginweb的文件夾下執行:scp -r * 10.0.0.102:/opt/、scp -r * 10.0.0.103:/opt/。
- 在兩臺生產機上運行代碼:cd /opt/-->./ginweb,這樣就運行起來了。
- 在瀏覽器上訪問10.0.0.102和103。
- 新建一臺機器(10.0.0.104)部署mysql和redis。修改mysql和redis 的遠程連接地址(修改配置文件)。vim /etc/redis/redis.conf,修改redis密碼和端口。重新啟動redis,redis-cli -a 123456 info。
- 【開發機】scp ginweb.sql 10.0.0.104
- 【數據庫機器】mysql -uginweb -p123456 -h 10.0.0.104 ginweb < ginweb.sql-->show tables,這時候就已經有表結構了。
- 【Jenkins網站】重新build Now,然后把文件同步到兩臺生產機上。再在兩臺生產機上跑起來ginweb。
- 以上都是手動部署。
- 【Jenkins機器】mkdir /data/jenkins-scripts、cd /data/jenkins-scripts/、vim ginweb.sh,添加兩臺生產機的IP地址。ssh-copy-id 10.0.0.102、ssh-copy-id 10.0.0.103。->應用。
- 更新下版本,修改掉登錄頁的標題的笑臉->3.0。在開發機上提交代碼。
- 在Jenkins網站中重新點擊Build Now。
綜上,完成的一個工作就是開發把代碼提交到gitlab上,Jenkins從gitlab拉取代碼,然后部署到生產環境跟中。
(二)Pipeline
Jenkins的流水線能自動化完成整個CI/CD流程,在Jenkins會顯示一條動態流水線:拉取代碼√->編譯打包√->代碼掃描√->部署√,哪個步驟出錯都會顯示紅色×。
- 從gitlab中拉取代碼。
- go build構建編譯
- go test自動化測試驗證
- SonarQube靜態掃描代碼
- docker build構建Docker鏡像
- subectl更新服務器/K8s
- 構建成功或失敗提醒,郵件/企業微信/飛書。
五、利用webHook實現自動化部署
這里將要實現當開發者提交代碼就會自動部署到生產環境中。
- 配置->觸發遠程構建->下面會有一串URL
- 【開發機】curl http://admin:xxx令牌【這個可以手動生成】@jenkins.wang.org:8080/job/ginweb/build?token=666666
- 【gitlab網站】設置->網絡->出站請求:允許來自web hooks和服務對本地網絡的請求。
- 【gitlab網站】設置->webhook->粘貼URL到網址部分->測試Push events->發現Jenkins上在執行。
- 【開發機】修改html中的標題改為v6.0,提交代碼到gitlab:git commit -am 'v6.0':git push -u origin master。理論上這里一提交就會觸發構建、觸發發布。
參考:
浙公網安備 33010602011771號