在軟體開發過程中,程式碼品質至關重要。程式碼風格檢查器固然能初步評估程式碼品質,但要深入分析程式碼並找出潛在錯誤和漏洞,仍需仰賴更強大的工具。我發現 SonarQube 正是這樣的利器,它整合了 PMD、Checkstyle 和 FindBugs 等工具,能全面分析程式碼函式庫的品質,並支援超過 20 種程式語言,例如 Java、PHP、Go 和 Python。
SonarQube 與 Jenkins 的完美結合
以下,我將分享如何將 SonarQube 整合到 Jenkins CI/CD Pipeline 中,開發更完善的程式碼分析流程。
建立 SonarQube 伺服器
首先,我們需要建立 SonarQube 伺服器。我選擇使用 Packer 烘焙一個新的 AMI,並以 Amazon Linux AMI 作為基礎,使用 Shell 指令碼安裝 SonarQube 和相關套件。
#!/bin/bash
# 安裝 SonarQube
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-8.2.0.zip -O /tmp/sonarqube.zip
unzip /tmp/sonarqube.zip -d /opt
mv /opt/sonarqube-8.2.0 /opt/sonarqube
# 安裝 PostgreSQL (作為 SonarQube 的資料函式庫)
# ... (PostgreSQL 安裝步驟)
# 設定 SonarQube
useradd sonar
chown -R sonar:sonar /opt/sonarqube
# ... (其他設定步驟)
# 設定開機啟動
# ... (systemd 設定)
接著,使用 Terraform 佈署一個以 SonarQube AMI 為基礎的 EC2 執行個體。
resource "aws_instance" "sonarqube" {
ami = "SonarQube AMI ID"
instance_type = "t2.medium"
# ... (其他設定)
}
resource "aws_lb" "sonarqube_lb" {
# ... (負載平衡器設定)
}
resource "aws_route53_record" "sonarqube" {
# ... (Route 53 設定)
}
執行 terraform apply
後,即可透過負載平衡器的 URL 存取 SonarQube 伺服器。預設的管理員帳號為 admin/admin
。
設定 Jenkins 與 SonarQube 掃描器
為了讓 Jenkins 能夠觸發 SonarQube 掃描,我們需要安裝 SonarQube 掃描器。可以直接在 Jenkins Worker 上安裝,或建立一個包含 SonarQube 掃描器的 Jenkins Worker 映像檔。
# 安裝 SonarQube 掃描器
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.2.0.1873-linux.zip -P /tmp
unzip /tmp/sonar-scanner-cli-4.2.0.1873-linux.zip
# ... (其他設定步驟)
在 Jenkins 中設定 SonarQube 伺服器的 URL 和驗證資訊。為了安全性,建議建立專用的 Jenkins 權杖,並將其儲存為 Jenkins 的「秘密鑰字組」憑證。
設定程式碼分析
在專案根目錄建立 sonar-project.properties
檔案,設定 SonarQube 掃描的引數。
sonar.projectKey=my-project
sonar.projectName=My Project
# ... (其他設定)
在 Jenkinsfile 中加入程式碼分析階段。
stage('程式碼分析') {
withSonarQubeEnv('sonarqube') {
sh 'sonar-scanner -Dsonar.projectVersion=$BUILD_NUMBER'
}
}
設定品質閘道
為了確保程式碼品質達到標準,我們可以設定品質閘道。品質閘道是一組規則,當程式碼未達標時,Pipeline 將會失敗。
stage('品質閘道') {
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate()
}
}
為了讓 Jenkins 知道 SonarQube 分析的完成狀態,需要在 SonarQube 中設定 Webhook,以便在分析完成時通知 Jenkins。
視覺化 Pipeline 流程
graph LR A[程式碼變更] --> B(Jenkins 觸發建置); B --> C{測試}; C -- 成功 --> D[SonarQube 程式碼分析]; D --> E{品質閘道}; E -- 透過 --> F[建置 Docker 映像檔]; E -- 失敗 --> G[停止建置];
透過整合 SonarQube 和 Jenkins,我們可以建立一個自動化的程式碼品質分析流程,及早發現程式碼問題,提升程式碼品質。在實務中,我建議定期執行程式碼分析,並將其整合到 CI/CD Pipeline 中,以確保程式碼的品質和安全性。
在現代軟體開發流程中,持續整合和持續交付 (CI/CD) 至關重要。Jenkins 作為一個廣泛使用的 CI/CD 工具,結合 Docker 的容器化技術,能大幅提升建置和佈署效率。本文將探討如何在 Jenkins CI Pipeline 中建置 Docker 映像檔,並分享一些最佳實務,讓你的建置流程更加高效和穩健。
Python 應用程式的 Docker 化
以 Python 為基礎的應用程式,我們可以選擇 python:3.7.3 作為基礎映像檔。利用 pip 管理相依性,並將 python main.py
設定為 Docker 映像檔的主要命令。
FROM python:3.7.3
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "main.py"]
- 此 Dockerfile 選擇
python:3.7.3
作為基礎映像檔,確保 Python 環境一致性。 - 首先複製
requirements.txt
,然後執行pip install
,利用 Docker 層級快取機制,加速後續建置。 - 最後複製應用程式碼,並設定啟動命令為
python main.py
。
為了確保映像檔建置的一致性,建議建立 requirements.txt
檔案,並使用明確的版本號碼來固定相依性。
在 Jenkinsfile 中,我們可以使用 Docker DSL 來建置映像檔:
stage('Build') {
docker.build(imageName)
}
Go 應用程式程式與多階段建置
對於 Go 應用程式,由於 Go 是編譯型語言,我們可以利用 Docker 的多階段建置功能來縮小映像檔大小。
FROM golang:1.16.5 AS builder
WORKDIR /go/src/github.com/mlabouardy/movies-parser
COPY main.go go.mod .
RUN go get -v
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app main.go
FROM alpine:latest
LABEL Maintainer mlabouardy
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/mlabouardy/movies-parser/app .
CMD ["./app"]
- 此 Dockerfile 使用多階段建置,第一階段使用
golang:1.16.5
編譯應用程式。 - 第二階段使用輕量級的
alpine:latest
作為基礎映像檔,僅複製編譯後的二進位檔,大幅縮小映像檔大小。
多階段建置能有效減少最終映像檔的大小,提升佈署效率。
Node.js 應用程式程式與相依性管理
對於 Node.js 應用程式,我們可以使用 node:14.17.0
作為基礎映像檔。
FROM node:14.17.0
WORKDIR /app
COPY package-lock.json package.json .
RUN npm i --only=prod
COPY index.js dao.js ./
EXPOSE 3000
CMD npm start
- 此 Dockerfile 使用
node:14.17.0
作為基礎映像檔。 - 首先複製
package-lock.json
和package.json
,確保相依性版本一致性,並利用 Docker 快取機制。 - 接著安裝生產環境所需的相依性,複製應用程式碼,並設定啟動命令。
Angular 應用程式程式與建置引數
對於 Angular 應用程式,我們同樣可以使用多階段建置,並使用建置引數來根據不同環境進行建置。
FROM node:14.17.0 as builder
ARG ENVIRONMENT
ENV CHROME_BIN=chromium
WORKDIR /app
RUN apt-get update && apt-get install -y chromium
COPY package-lock.json package.json .
RUN npm i && npm i -g @angular/cli
COPY . .
RUN ng build -c $ENVIRONMENT
FROM nginx:alpine
RUN rm -rf /usr/share/nginx/html/*
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
- 此 Dockerfile 使用多階段建置,第一階段使用
node:14.17.0
建置 Angular 應用程式。 - 使用
ARG ENVIRONMENT
允許在建置時傳入環境變數,用於不同環境的建置。 - 第二階段使用
nginx:alpine
作為基礎映像檔,提供靜態檔案服務。
在 Jenkinsfile 中,我們可以這樣傳遞建置引數:
stage('Build'){
docker.build(imageName, '--build-arg ENVIRONMENT=sandbox .')
}
.dockerignore 檔案
使用 .dockerignore
檔案可以排除不需要複製到 Docker 映像檔中的檔案和目錄,例如 node_modules
、coverage
、dist
和 tmp
等。
node_modules
coverage
dist
tmp
本文介紹瞭如何在 Jenkins CI Pipeline 中建置不同型別應用程式的 Docker 映像檔,並分享了多階段建置、Docker 建置引數和 .dockerignore
檔案等最佳實務。透過這些技巧,可以有效減少映像檔大小、提升建置效能,並構建更穩健的 CI/CD 流程。在實際應用程式中,我推薦使用 Docker Compose 來管理多容器應用程式的建置,更進一步提升效率。
NEXUS_USERNAME="admin"
NEXUS_PASSWORD="admin123"
# 安裝 Java JDK 8
yum update -y
yum install -y java-1.8.0-openjdk
# 安裝 Nexus OSS
wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz -P /tmp
tar -xvf /tmp/latest-unix.tar.gz
# 設定 Nexus 使用者和目錄許可權
mv nexus-* /opt/nexus
mv sonatype-work /opt/sonatype-work
useradd nexus
chown -R nexus:nexus /opt/nexus/ /opt/sonatype-work/
# 設定 Nexus 服務
ln -s /opt/nexus/bin/nexus /etc/init.d/nexus
chkconfig --add nexus
chkconfig --levels 345 nexus on
mv /tmp/nexus.rc /opt/nexus/bin/nexus.rc
echo "nexus.scripts.allowCreation=true" >> nexus-default.properties
systemctl enable nexus
systemctl start nexus
這段 Shell 指令碼完成了 Java JDK 8 和 Nexus Repository OSS 的安裝與初始設定。首先,它更新系統套件,接著安裝 OpenJDK 8。然後,下載 Nexus OSS 的壓縮檔,解壓縮並移動到 /opt
目錄。為了確保 Nexus 的正常執行,指令碼建立了一個名為 nexus
的使用者,並將 /opt/nexus
和 /opt/sonatype-work
的所有權賦予該使用者。最後,它建立了 Nexus 服務的啟動連結,並設定其開機自動啟動。
until $(curl --output /dev/null --silent --head --fail http://localhost:8081); do
printf '.'
sleep 2
done
這段程式碼的功能是持續檢查 Nexus 服務是否已啟動並正在執行。它使用 curl
命令傳送 HTTP HEAD 請求到 http://localhost:8081
,並檢查伺服器的回應。如果伺服器沒有回應,則列印一個點 .
,並等待 2 秒後再次嘗試。直到伺服器成功回應,迴圈才會結束,表格示 Nexus 服務已準備就緒。
curl -v -X POST -u $NEXUS_USERNAME:$NEXUS_PASSWORD \
--header "Content-Type: application/json" 'http://localhost:8081/service/rest/v1/script' \
-d @/tmp/repository.json
這段程式碼使用 curl
命令向 Nexus Script API 傳送一個 POST 請求,以建立 Docker 託管儲存函式庫。-u
選項指定了 Nexus 的使用者名稱和密碼,-H
選項設定了請求的 Content-Type 為 application/json
,-d
選項指定了請求的資料來自 /tmp/repository.json
檔案。
import org.sonatype.nexus.blobstore.api.BlobStoreManager;
import org.sonatype.nexus.repository.storage.WritePolicy;
repository.createDockerHosted('docker-registry', 5000, 443, BlobStoreManager.DEFAULT_BLOBSTORE_NAME, true, true, WritePolicy.ALLOW, true)
這段 Groovy 指令碼定義瞭如何建立 Docker 託管儲存函式庫。它使用了 repository.createDockerHosted
方法,並傳遞了儲存函式庫的名稱、HTTP 連線埠、HTTPS 連線埠、Blob 儲存區名稱以及其他設定引數。
resource "aws_instance" "nexus" {
ami = data.aws_ami.nexus.id
instance_type = var.nexus_instance_type
key_name = var.key_name
vpc_security_group_ids = [aws_security_group.nexus_sg.id]
subnet_id = element(var.private_subnets, 0)
root_block_device {
volume_type = "gp2"
volume_size = 50
delete_on_termination = false
}
tags = {
Author = var.author
Name = "nexus"
}
}
這段 Terraform 程式碼定義了一個 AWS EC2 執行個體資源,用於執行 Nexus Repository OSS。它指定了 AMI ID、執行個體型別、金鑰名稱、安全群組、子網路 ID 以及根區塊裝置的設定。此外,它還設定了執行個體的標籤,方便管理和識別。
透過 Packer 建立 Nexus OSS AMI 後,我們可以使用 Terraform 將其佈署到 AWS。設定負載平衡器和 DNS 記錄後,即可透過瀏覽器存取 Nexus Repository Manager 儀錶板。
這篇文章示範瞭如何使用 Packer 和 Terraform 自動化構建和佈署 Nexus Repository OSS 的過程。透過自動化,我們可以更快速、更可靠地佈署和管理基礎設施,提高效率並降低錯誤率。