前言
今年因為 docker hub 用起來太不開心、客服有夠雷,
問三個問題只回答一個,後續就開始水,最後就要回不回了。
想說不如把付費版的錢補回 ec2,決定自己建 CI server。
目前 docker hub 提供的功能有兩個:CI 以及 image registry。
CI: Drone CI
查了各式各樣的解決方案,看起來小規模目前很適合用 Drone CI,簡單輕量又好用。
不考慮 GHA (Github Action),因為
- 有額度限制,另外也都決定要自己 host CI server 了,運算資源都是自己的,沒有額度問題。
- 就算可以 self-hosting GHA runner,以過去開發 pipeline 的經驗,感受不是很順暢。
對我自己的專案來說,我傾向只把 Github 當作 git repo,其他功能都不要用。
如果未來採用 monorepo,那可能還是得使用 GHA,
因為 Drone CI 對於 monorepo 控制的顆粒度比較差。
Image Registry: docker registry
資源有限,我有考慮過幾個方案:
- Sonatype Nexus:公司用過這個,整體來說挺不錯。可以同時放 image 跟 python, node 套件。
但以我自己的專案規模而言,這個方案太重型了。
- Harbor:乍看了幾個評價,似乎不是很好用,說不定是過時的評論,但我不想冒險。
- Gitea:沒錯 Gitea 有內建 registry。原本是我的首選,後來考慮到 git 的部分有點重疊,
最後決定延用 Github 儲存程式碼以及處理 Auth。這樣的話 Gitea 只為了 registry 似乎有點浪費。
如果自己開公司全部自己 host 的話,絕對會用 Gitea + Drone CI。
現階段就先拿 registry
擋著用吧。
主機考量
Drone CI 是由 Server 與 Runner 組成 (CI 都差不多是這樣)。
考量到目前的流量與成本,我決定不另外開 ec2 去 host CI server,
直接把他跟 prod 服務放在同一個 k3s cluster 上。
一方面可以加大 CPU 使用效率,等到流量大起來撐不住再考慮移轉;
一方面可以把 build 好的 image 直接在同一個 cluster 上啟用,節省硬碟空間。
架構
既然要裝在 k3s (K8s),用 helm
安裝 server 以及 runner 自然是最方便的選擇。
另外,目前 cluster 中有安裝 cert manager,所以除了原有的 helm
安裝的資源之外,
要自己額外補上 cert
資源,
就不去像一般文件說明使用 NodePort
的方式連接,
而是直接新增 route53 的 A Record,用 https
直接連到建立的 Drone CI Server。
當 CI server 觸發 github 事件之後,
同樣把 build request 發給同一個 cluster 中的 runner,
直接在同一個 cluster 完成 build。
簡單的架構圖像是這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
┌─────────────────────────────┐
│ k3s cluster │
│ │
│ │
│ ┌───────────────────┐ │
│ │ │ │
│ │ drone server │ │
│ │ │ │
│ └───┬────────────┬──┘ │
│ │ │ │
│ │ request │ │
│ │ │ │
│ ┌───▼────┐ ┌────▼───┐ │
│ │ │ │ │ │
│ │ drone │ │ drone │ │
│ │ runner │ │ runner │ │
│ │ │ │ │ │
│ └──┬─────┘ └──────┬─┘ │
│ │ │ │
│ build │ ┌────────┐ │ │
│ └► │ images ││ ◄┘ │
│ └┬───────┘│ │
│ └────────┘ │
│ │ │
│ push │ │
│ │ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ │ │
│ │ registry │ │
│ │ │ │
│ └───────────────────┘ │
│ ▲ │
│ │ pull │
│ ┌──┘ │
│ ┌────┴────────┐ │
│ │ │ │
│ │ deployments │ │
│ │ │ │
│ └─────────────┘ │
│ │
└─────────────────────────────┘
|
Github?
Drone CI server 要串接 Github:
一方面是要獲得 repo 的 event,用來觸發 CI、test、build,
另一方面也是順便用 Github OAuth 驗證 user。
安裝 Drone CI Server
安裝 server 的部分主要參考 REF [1]
先決定 CI server domain
因為這個 CI server 沒有打算要給所有人使用,
也因為共用 cluster,不想在 aws 額外處理網路白名單,
所以直接用一個亂數當作 host 當作暫時的解決方式:
1
2
|
openssl rand -hex 16
d485238e29ad124123ed0c2df363515c
|
所以這個 CI server 的 FQDN 就直接變成:
d485238e29ad124123ed0c2df363515c.mydomain.com
DNS A record
然後在你的 DNS 供應商平台上面新增一個 A record,像是:
d485238e29ad124123ed0c2df363515c.mydomain.com. --> <your server ip>
Github 註冊 OAuth application
在 github 新增 app
Settings
> Developer Settings
> Register a new OAuth application
然後把剛剛的 FQDN 填進去,要加上 scheme https://
設定完成之後會有 Client ID
,記得先複製下來。
接著也要點選 Generate a new client secret
的按鈕,然後也把結果複製下來。
server 內設定 helm values
進入 server 的環境,在你喜歡的路徑下載 values.yaml
:
1
2
3
|
mkdir droneci
curl -s https://raw.githubusercontent.com/drone/charts/refs/heads/master/charts/drone/values.yaml > values.yaml
|
(這個 values.yaml
取自 REF [2])
然後 vim values.yaml
編輯以下的地方
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
# ...
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: letsencrypt-production
hosts:
- host: d485238e29ad124123ed0c2df363515c.mydomain.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: ci-tls
hosts:
- d485238e29ad124123ed0c2df363515c.mydomain.com
# ...
resources:
requests:
cpu: 100m
memory: 128Mi
# ...
env:
DRONE_SERVER_HOST: "d485238e29ad124123ed0c2df363515c.mydomain.com"
DRONE_SERVER_PROTO: https
DRONE_RPC_SECRET: e4eaeb0fb3d1b4d1c78d8c5f85906600eeb0c1e0073aeb84
DRONE_GITHUB_CLIENT_ID: TrAe4IFcWAhhB5QKMhS4
DRONE_GITHUB_CLIENT_SECRET: 37154fa1aadcaf5a0f2152d7d07c789d
|
Note
-
DRONE_GITHUB_CLIENT_ID
、DRONE_GITHUB_CLIENT_SECRET
,
就是先前 OAuth application 步驟的 Client ID
、Client Secret
。
-
DRONE_RPC_SECRET
可以自己用亂產生,像是前面提到的 openssl rand -hex 16
-
因為 cluster 有 cert manager,且我打算新增 cert
資源綁定 tls secret 稱為 ci-tls
,
如果有其他名字就自行調整。
-
預設的 persistentVolume.size
是 8Gi
,可以自己調整;我這邊先用預設。
補上 cert
先驗證 domain 可以解析
在新增 cert
之前,要先確認 DNS 有 A Record,而且解析得到:
1
|
nslookup d485238e29ad124123ed0c2df363515c.mydomain.com
|
新增 cert yaml
因為有安裝了 cert manager,所以可以新增 cert
資源,
可以用來自動驗證憑證以及新增 tls secret。
vim cert.yaml
:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ci-tls
namespace: drone
spec:
dnsNames:
- d485238e29ad124123ed0c2df363515c.mydomain.com
issuerRef:
group: cert-manager.io
kind: ClusterIssuer
name: letsencrypt-production
secretName: ci-tls
|
然後 apply
它:
1
|
kubectl apply -f cert.yaml
|
觀察 cert 結果,等到 READY
變成 True
就可以了:
1
2
3
4
|
# kubectl get cert -n drone -w
NAME READY SECRET AGE
ci-tls True ci-tls 93m
|
萬事俱備,一氣呵成
完成 values.yaml
的修改後,就可以透過 helm install
命令來安裝了:
1
2
|
kubectl create ns drone
helm install drone drone/drone --namespace drone -f values.yaml
|
結果類似這樣:
1
2
3
4
5
6
7
8
9
|
NAME: drone
LAST DEPLOYED: Sat Sep 21 05:44:03 2024
NAMESPACE: drone
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
https://d485238e29ad124123ed0c2df363515c.mydomain.com
|
用瀏覽器打開設定的 URL,就可以進入 server 的網頁了。
安裝 Drone CI Runner
目前在網路上搜尋了一下沒有找到比較完整的文件可以抄 ,所以只好自己準備 helm
template。
用 helm 安裝
我直接沿用前面安裝 DroneCI server 的資料夾,在他底下新增一個 runner/
,
用來渲染 DroneCI Runner 相關的 helm template。
所以目前資料夾長得像這樣:
1
2
3
4
5
6
7
8
9
|
.
├── cert.yaml
├── runner
│ ├── Chart.yaml
│ ├── templates
│ │ ├── deployment.yaml
│ │ └── rbac.yaml
│ └── values.yaml
└── values.yaml
|
如果想拆乾淨一點可以自行在另一個資料夾處理。
如果想看完整一點結構,可以用 helm create
一個完整的範例專案。
這邊簡單起見就直接放在一起。
東西不多,主要就三部分:
Chart.yaml
values.yaml
templates/
deployments.yaml
rbac.yaml
可以手動貼上:
Chart.yaml
1
2
3
4
5
6
|
apiVersion: v2
name: droneci-runner
description: DroneCI Runner
type: application
version: 0.1.0 # 目前借用 helm 渲染用,可以不用維護版本
appVersion: "1.16.0" # 目前借用 helm 渲染用,可以不用維護版本
|
values.yaml
1
2
3
4
5
6
|
# 這邊沒有要對外,用 Kubernetes 內網的 CI server 的 service 連接即可。
drone_rpc_host: droneci.droneci:8080
drone_rpc_proto: http
# 要跟前一步驟中 server 的 DRONE_RPC_SECRET 相同
drone_rpc_secret: e4eaeb0fb3d1b4d1c78d8c5f85906600eeb0c1e0073aeb84
|
templates/deployments.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: drone
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: drone
template:
metadata:
labels:
app.kubernetes.io/name: drone
spec:
containers:
- name: runner
image: drone/drone-runner-kube:latest
ports:
- containerPort: 3000
env:
- name: DRONE_RPC_HOST
value: {{ .Values.drone_rpc_host }}
- name: DRONE_RPC_PROTO
value: {{ .Values.drone_rpc_proto }}
- name: DRONE_RPC_SECRET
value: {{ .Values.drone_rpc_secret }}
- name: DRONE_NAMESPACE_DEFAULT
value: {{ .Release.Namespace }}
serviceAccount: {{ .Release.Name }}
|
一開始沒有加上 DRONE_NAMESPACE_DEFAULT
,
跑起來之後一直抱怨 default
namespace 不能 create secrets,
後來終於在 REF [3] 找到這個環境變數。
templates/rbac.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Release.Name }}
namespace: {{ .Release.Namespace }}
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: {{ .Release.Namespace }}
name: {{ .Release.Name }}
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- delete
- apiGroups:
- ""
resources:
- pods
- pods/log
verbs:
- get
- create
- delete
- list
- watch
- update
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ .Release.Name }}
namespace: {{ .Release.Namespace }}
subjects:
- kind: ServiceAccount
name: {{ .Release.Name }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: Role
name: {{ .Release.Name }}
apiGroup: rbac.authorization.k8s.io
|
最後直接 helm
安裝:
1
|
helm upgrade -i droneci-runner -n drone .
|
- 我習慣用
upgrade
,這樣可以安裝更新都用同一組指令。
新增「暫時測試」的 pipeline yaml
在當前專案裡面新增一個 branch,
然後在最上層目錄新增 .drone.yaml
並放入 pipeline 的 yaml。
pipeline 可以參考 REF [4],以我 Python API 的專案來說會類似這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
kind: pipeline
type: kubernetes
name: default
steps:
- name: test
image: python:3.12-slim
environment:
API_HOST: localhost
API_PORT: 8080
DB_USER: ci
DB_PASSWORD:
from_secret: DB_PASSWORD
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: 30
JWT_REFRESH_TOKEN_EXPIRE_MINUTES: 1440
JWT_ALGORITHM: HS256
JWT_SECRET_KEY: xxx
JWT_SECRET_REFRESH_KEY: yyy
HOST_NAME: localhost
commands:
- echo "debug ---" && env
- pip install -r requirements.txt
|
commit 之後 push。
由於目前沒有限制 branch,所以 push 之後就會觸發執行。
到先前設定的 DRONE_SERVER_HOST
查看,
例如 https://d485238e29ad124123ed0c2df363515c.mydomain.com
點擊歷程查看內容
⬆︎ 前兩次失敗就是因為前面沒有指定到 DRONE_NAMESPACE_DEFAULT
環境變數,
導致權限不正確直接噴錯。
現在可以依照自己需要的 CI 步驟去更新 .drone.yaml
裡面的 pipeline,例如:
- 跑
pytest
- 驗證環境變數可以連線到測試用 DB
目前這個範例 YAML 會說是「暫時測試」,原因是我們的 registry 還沒有建立,
如果5此時要 build
image 會沒辦法指定 image registry。
現階段只能測試 commit、push 後是否有正確觸發 CI;
在建立 registry 之後會再更新 pipeline.yaml
,讓 build
的流程一併加入,詳見下一節。
安裝 Registry
原本一度考慮看能不能把 image 推在 local k3s cluster,
後來想想還是獨立開來,因為之後 CI 跟 registry 有可能會在其他台主機上面,
保留處理的彈性。
不過這樣限於硬碟空間大小,要額外做 housekeeping。
製作 registry 的帳號密碼
用 htpasswd
指令產生 registry 的帳號密碼:
1
2
3
4
5
6
|
htpasswd -Bbn demo bf69d401df35bedad6f7d83f0cac18f0
# ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# username password
# result
demo:$2y$05$2kkHyxUkq.izxOWbOlqW3ePJkzG/WhuJCbPrdiOixXtIo/QvQjf/2
|
Note
- 密碼可以自行更改
- 我是用
openssl rand -hex 16
產生的亂數
如果你的電腦或 server 沒有 htpasswd
,可以:
- 安裝指令,各平台指令參考 https://command-not-found.com/htpasswd
1
2
3
4
5
|
# CentOS
yum install httpd-tools
# Ubuntu
apt-get install apache2-utils
|
- 或用 docker 直接執行
1
2
3
4
5
6
7
8
9
10
|
docker run --rm cmd.cat/htpasswd htpasswd -Bbn demo bf69d401df35bedad6f7d83f0cac18f0
# Unable to find image 'cmd.cat/htpasswd:latest' locally
# latest: Pulling from htpasswd
# 7264a8db6415: Pull complete
# 3b63c57d36dd: Pull complete
# dbc368251d6c: Pull complete
# 2a456f825220: Pull complete
# Digest: sha256:05a4ef9d5eb70d2252778d3d66835ece1b62f169c2d5f37b04253ce7bc9ecdd4
# Status: Downloaded newer image for cmd.cat/htpasswd:latest
demo:$2y$05$2id3XHub8tl7HYmx5Eih5OC90RbipWQuGpBRLx3UY8SLio9VeHHnm
|
把密碼存成 secret
先創建一個 namespace 用來放 registry 相關的資源:
1
|
kubectl create ns docker-registry
|
然後 create secret 存放剛剛用 htpasswd
製作的內容:
1
2
3
4
|
kubectl -n docker-registry create secret generic registry-htpasswd \
--from-literal=USERNAME=demo \
--from-literal=PASSWORD=bf69d401df35bedad6f7d83f0cac18f0 \
--from-literal=HTPASSWD="demo:$2y$05$2id3XHub8tl7HYmx5Eih5OC90RbipWQuGpBRLx3UY8SLio9VeHHnm"
|
準備 pvc, deployment, svc
pvc.yaml
:
1
2
3
4
5
6
7
8
9
10
11
|
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: docker-registry
namespace: docker-registry
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
|
因為有 storage class (local-path),所以不用處理 pv。
deployment.yaml
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: registry
name: registry
namespace: docker-registry
spec:
replicas: 1
selector:
matchLabels:
app: registry
template:
metadata:
labels:
app: registry
spec:
containers:
- image: registry:2.8.3
name: registry
volumeMounts:
- name: registry-pvc
mountPath: "/var/lib/registry"
- name: htpasswd
mountPath: /etc/auth/htpasswd
env:
- name: REGISTRY_AUTH
value: "htpasswd"
- name: REGISTRY_AUTH_HTPASSWD_REALM
value: "Registry Realm"
- name: REGISTRY_AUTH_HTPASSWD_PATH
value: "/etc/auth/htpasswd/HTPASSWD"
- name: REGISTRY_STORAGE_DELETE_ENABLED
value: "true"
volumes:
- name: registry-pvc
persistentVolumeClaim:
claimName: docker-registry
- name: htpasswd
secret:
secretName: registry-htpasswd
|
Note
- 先前建立的 secret
htpasswd
要設定。
概念上是先
volumes
from secret (registry-htpasswd
)
–> mount 指定路徑 (/etc/auth/htpasswd
)
–> 環境變數 REGISTRY_AUTH_HTPASSWD_PATH
要指定該路徑
- 考量到會需要做 housekeeping,要把
REGISTRY_STORAGE_DELETE_ENABLED
設定為 true
svc.yaml
:
1
2
3
4
5
6
7
8
9
10
11
|
apiVersion: v1
kind: Service
metadata:
name: registry
namespace: docker-registry
spec:
selector:
app: registry
ports:
- port: 5000
targetPort: 5000
|
以這個 svc 的設定來說,最後內網連線的 registry 就會是
registry.docker-registry.svc:5000
設定 cert, ingress
原本考慮內網 registry 就好,後來發現直接設定的話 deployments 會認不到,出現 ImagePullBackOff
。
考量到之後還是有可能把 CI server 與 registry 放在另外一組 cluster 上,
所以現在就改成外網的 domain 當作 registry 沒有不好。
現在要補上 certs 以及 ingress。
certs.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cr-tls
namespace: docker-registry
spec:
dnsNames:
- d485238e29ad124123ed0c2df363515c0-my-cr.mydomain.com
issuerRef:
group: cert-manager.io
kind: ClusterIssuer
name: letsencrypt-production
secretName: cr-tls
usages:
- digital signature
- key encipherment
|
ingress.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 1500m # avoid 413 request entity too large
name: registry
namespace: docker-registry
spec:
ingressClassName: nginx
rules:
- host: d485238e29ad124123ed0c2df363515c0-my-cr.mydomain.com
http:
paths:
- backend:
service:
name: registry
port:
number: 5000
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- d485238e29ad124123ed0c2df363515c0-my-cr.mydomain.com
secretName: cr-tls
|
- 可以考慮把
proxy-body-size
改成 0
,不檢查大小。
- 一定要設定 body size,不然 image 隨便推經過 nginx 都會報
413
(request entity too large)
Housekeeping: 清理 Drone CI Server 以及 registry 的資料
如果需要完整稽核紀錄,是我的話會直接付錢採用雲端服務,省事多了。
本篇不屬於這個案例,自建、自用以經濟實惠為主,不用考慮稽核紀錄,
東西都放在同一台 server,資源有限,及時做清理可以減少硬碟的成本。
清理 Drone CI Server 的歷程紀錄
預設 Drone CI 是用 sqlite 的資料庫來做紀錄,
1
2
3
|
apk add sqlite
sqlite3 /data/database.sqlite
|
只保留近 20 次的 build
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
DELETE FROM logs WHERE log_id IN (
SELECT step_id FROM steps WHERE step_stage_id IN (
SELECT stage_id FROM stages WHERE stage_build_id IN (
SELECT build_id
FROM repos, builds
WHERE repo_id = build_repo_id
AND build_number < repo_counter - 20
)
)
);
DELETE FROM stages WHERE stage_build_id IN (
SELECT build_id
FROM repos, builds
WHERE repo_id = build_repo_id
AND build_number < repo_counter - 20
);
DELETE FROM builds WHERE build_id IN (
SELECT build_id
FROM repos, builds
WHERE repo_id = build_repo_id
AND build_number < repo_counter - 20
);
-- Reclaim space and optimize the database
VACUUM;
|
套用 Cronjob 幫忙自動觸發:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
apiVersion: batch/v1
kind: CronJob
metadata:
name: drone-housekeeping
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: drone-housekeeping
image: alping/sqlite:latest
volumeMounts:
- name: drone-data
mountPath: /data
command: ["/bin/sh", "-c"]
args:
- |
sqlite3 /data/database.sqlite <<EOF
DELETE FROM logs WHERE log_id IN (
SELECT step_id FROM steps WHERE step_stage_id IN (
SELECT stage_id FROM stages WHERE stage_build_id IN (
SELECT build_id
FROM repos, builds
WHERE repo_id = build_repo_id
AND build_number < repo_counter - 20
)
)
);
DELETE FROM stages WHERE stage_build_id IN (
SELECT build_id
FROM repos, builds
WHERE repo_id = build_repo_id
AND build_number < repo_counter - 20
);
DELETE FROM builds WHERE build_id IN (
SELECT build_id
FROM repos, builds
WHERE repo_id = build_repo_id
AND build_number < repo_counter - 20
);
-- Reclaim space and optimize the database
VACUUM;
EOF
restartPolicy: OnFailure
volumes:
- name: drone-data
persistentVolumeClaim:
claimName: storage-volume # 安裝 Drone CI 時的 PVC
|
清理 registry 的資料
一般情況直接進入 pod 執行
1
2
3
|
kubectl -n docker-registry exec -it \
$(kubectl -n docker-registry get pod -l app=registry -oname) \
-- registry garbage-collect /etc/docker/registry/config.yml -m
|
如果想定期執行可以考慮包成 cronjob。
Note
- 如果要包成 kubernetes cronjob 資源,就需要把 docker 的
config.yaml
包成 configmap,然後共用;想想覺得太麻煩,就先直接在外面用指令執行。
大功告成:最後更改 Drone CI 的 yaml
現在已經可以完成觸發,只要把流程改成自己的理想的狀態就可以了。
我的目標是:
- 只有在 PR 開起來以及後續 synchronize 了才觸發 CI,並且發出通知。
- 只有在押上 tag 之後才會 build
- build 完成之後通知 keel 觸發 deploy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
kind: pipeline
type: kubernetes
name: default
clone:
depth: 1
trigger:
event:
- pull_request
action:
- opened
- synchronized
steps:
- name: ci
image: python:3.12-slim
environment:
ENV: DEV
API_HOST: localhost
API_PORT: 8080
API_DOCS_URL_PREFIX: "test"
API_DOCS_ENABLED: 1
API_SERVER_URL_PREFIX_IN_DOCS: ""
API_MONGODB_COLLECTIONS_SUFFIX: "_edge"
MONGODB_USER: ci-user
MONGODB_PASSWORD:
from_secret: MONGODB_PASSWORD
MONGODB_URI:
from_secret: MONGODB_URI
MONGODB_DATABASE: testDB
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: 1
JWT_REFRESH_TOKEN_EXPIRE_MINUTES: 1440
JWT_ALGORITHM: HS256
JWT_SECRET_KEY: "secretkeyforci"
JWT_SECRET_REFRESH_KEY: "refreshkeyforci"
HOST_NAME: localhost
commands:
- export PATH="$HOME/.local/bin:$PATH"
- pip install pipx && pipx install poetry && poetry install
- poetry run pytest || exit 1
- name: notify
image: plugins/slack
settings:
webhook:
from_secret: SLACK_WEBHOOK
message: |
REPO: `${DRONE_REPO}`
source -> target: `${DRONE_SOURCE_BRANCH}` -> `${DRONE_TARGET_BRANCH}`
build link: ${DRONE_BUILD_LINK}
when:
status:
- success
- failure
---
kind: pipeline
type: kubernetes
name: tag-build
clone:
depth: 1
trigger:
event:
- tag
steps:
- name: build
image: plugins/docker
settings:
username:
from_secret: REGISTRY_USER
password:
from_secret: REGISTRY_PASSWORD
registry: d485238e29ad124123ed0c2df363515c0-my-cr.mydomain.com
insecure: true
repo: d485238e29ad124123ed0c2df363515c0-my-cr.mydomain.com/my-repo
dockerfile: ./Dockerfile
tags:
- ${DRONE_TAG}
- latest
- name: deploy
image: plugins/webhook
# ref: https://keel.sh/docs/#webhooks
settings:
urls: http://keel.kube-system.svc:9300/v1/webhooks/native
content_type: application/json
template: |
{
"name": "d485238e29ad124123ed0c2df363515c0-my-cr.mydomain.com/my-repo",
"tag": "${DRONE_TAG}"
}
|
Note
- 因為原本就有裝 keel;如果直接觸發 helm 等方式部署也是可以的。
REF
- https://dev.to/neelanjan00/how-to-install-drone-ci-in-kubernetes-39e5
- https://github.com/drone/charts/blob/master/charts/drone/values.yaml
- https://docs.drone.io/runner/vm/configuration/reference/drone-namespace-default/
- https://docs.drone.io/pipeline/kubernetes/examples/language/python/#test-multiple-architectures
- https://medium.com/swlh/deploy-your-private-docker-registry-as-a-pod-in-kubernetes-f6a489bf0180
- https://stackoverflow.com/questions/46545705/how-to-set-retention-policy-in-drone-ci