[Kubernetes] ๐งน GitHub Actions Runner Pod ๋์คํฌ ์ ๋ฆฌ: kubectl exec + docker prune ์ผ๊ด ์คํ
Kubernetes์ ์ฌ๋ฆฐ GitHub Actions self-hosted runner Pod์ ์์ธ Docker ๋น๋ ์ฐ๊บผ๊ธฐ๋ฅผ, label selector์ xargs๋ก ์ฌ๋ฌ Pod์ ํ ๋ฒ์ docker system prune ํ๋ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํ์ต๋๋ค.
Kubernetes์ ์ฌ๋ฆฐ GitHub Actions self-hosted runner๋ CI ๋น๋๋ฅผ ๋ฐ๋ณตํ๋ฉด์ Docker ์ด๋ฏธ์งยท๋น๋ ์บ์๊ฐ ์์ฌ ๋
ธ๋ ๋์คํฌ๋ฅผ ๊ฐ๋ ์ฑ์ฐ๊ธฐ ์ฝ์ต๋๋ค. ์ด ๊ธ์์๋ kubectl get pods -l๋ก runner Pod๋ฅผ ๊ณจ๋ผ xargs๋ก ๋ฌถ์ด, ์ฌ๋ฌ Pod์ ํ ๋ฒ์ docker system prune์ ์คํํ๋ ํ ์ค ๋ช
๋ น์ด๋ฅผ ๋ถํดํ๊ณ , ์์ ํ ์ต์
์ ํ๊ณผ CronJob ์๋ํ๊น์ง ์ค๋ฌด ๊ด์ ์ผ๋ก ์ ๋ฆฌํฉ๋๋ค.
๐ฏ ํต์ฌ ๋ช ๋ น์ด ํ ์ค
1
2
kubectl get -n github-runner pods -l app=githubrunner-cs -o name \
| xargs -I {} kubectl exec -n github-runner {} -c githubrunner-cs -- docker system prune -f
์ด ํ ์ค์ github-runner ๋ค์์คํ์ด์ค์์ app=githubrunner-cs ๋ผ๋ฒจ์ด ๋ถ์ ๋ชจ๋ runner Pod๋ฅผ ์ฐพ์, ๊ฐ Pod์ githubrunner-cs ์ปจํ
์ด๋ ์์์ docker system prune -f๋ฅผ ์คํํฉ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ๋ชจ๋ runner์ Docker ์ฐ๊บผ๊ธฐ๋ฅผ ํ ๋ฒ์ ์ ๋ฆฌํฉ๋๋ค.
๐ง ์ runner Pod์ ์ฐ๊บผ๊ธฐ๊ฐ ์์ผ๊น?
self-hosted runner๋ CI ๋น๋๋ง๋ค Docker ์ด๋ฏธ์ง๋ฅผ ๋ฐ๊ณ ๋น๋ ์บ์๋ฅผ ๋จ๊ธฐ๋๋ฐ, ์ด๊ฒ ์ ๋ฆฌ๋์ง ์๊ณ ๋์ ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ํนํ runner Pod ์์์ Docker ๋น๋๋ฅผ ๋๋ฆฌ๋ DinD(Docker-in-Docker) ๊ตฌ์กฐ์์๋ ๋ค์์ด ์์ ๋๋ค.
- ๋น๋ ์ค๊ฐ ๋จ๊ณ ์ด๋ฏธ์ง์ dangling ์ด๋ฏธ์ง(ํ๊ทธ๊ฐ ๋จ์ด์ง
<none>์ด๋ฏธ์ง) docker build๊ณผ์ ์์ ์๊ธฐ๋ ๋น๋ ์บ์- ์ข ๋ฃ๋ ์ปจํ ์ด๋, ์ฌ์ฉํ์ง ์๋ ๋คํธ์ํฌ
GitHub Actions์ ๊ณต์ ํธ์คํฐ๋ runner๋ ๋งค๋ฒ ๊นจ๋ํ VM์์ ์์ํ์ง๋ง, self-hosted runner๋ ํ๊ฒฝ์ด ์ ์ง๋๋ฏ๋ก ์ง์ ์ฒญ์ํ์ง ์์ผ๋ฉด ๊ณ์ ๋์ ๋ฉ๋๋ค. ๊ฒฐ๊ตญ ๋
ธ๋์ ๋์คํฌ๊ฐ ๊ฐ๋ ์ฐจ๋ฉด ImagePull ์คํจ๋ Pod Evicted๋ก ์ด์ด์ง๋๋ค.
โ ๏ธ ๋์คํฌ๊ฐ ์ด๋ฏธ ๊ฐ๋ ์ฐฌ ๋ค์๋ Pod๊ฐ
Evicted๋์ด ์ ๋ฆฌ ๋ช ๋ น์กฐ์ฐจ ๋ชป ๋ค์ด๊ฐ ์ ์์ต๋๋ค. ์ฃผ๊ธฐ์ ์ ๋ฆฌ(์๋ํ)๊ฐ ํต์ฌ์ ๋๋ค.
๐ฌ ๋ช ๋ น์ด ํ ์ค ๋ถํดํ๊ธฐ
๋ช ๋ น์ด๋ ์ธ ํ ๋ง์ผ๋ก ๋๋ ๋ณด๋ฉด ๋ช ํํฉ๋๋ค.
1๏ธโฃ ๋์ Pod ๊ณ ๋ฅด๊ธฐ โ kubectl get -l
1
kubectl get -n github-runner pods -l app=githubrunner-cs -o name
-l app=githubrunner-cs๋ label selector๋ก runner Pod๋ง ์ ํํฉ๋๋ค. -o name์ ์ถ๋ ฅ์ pod/์ด๋ฆ ํ์์ผ๋ก ๋จ์ํํด ๋ค์ ๋จ๊ณ์ ๋๊ธฐ๊ธฐ ์ข๊ฒ ๋ง๋ญ๋๋ค.
1
2
3
pod/githubrunner-cs-0
pod/githubrunner-cs-1
pod/githubrunner-cs-2
2๏ธโฃ ๊ฐ Pod๋ก ํผ์น๊ธฐ โ xargs -I {}
1
| xargs -I {} kubectl exec ... {} ...
xargs -I {}๋ ์ ๋จ๊ณ์์ ๋ฐ์ ์ค(Pod ์ด๋ฆ)์ ํ๋์ฉ {} ์๋ฆฌ์ ๋ผ์ ๋ฃ์ด ๋ช
๋ น์ Pod ๊ฐ์๋งํผ ๋ฐ๋ณตํฉ๋๋ค. Pod๊ฐ 3๊ฐ๋ฉด kubectl exec๊ฐ 3๋ฒ ์คํ๋ฉ๋๋ค.
3๏ธโฃ ์ปจํ
์ด๋ ์์์ ์คํ โ kubectl exec -c ... -- docker ...
1
kubectl exec -n github-runner pod/githubrunner-cs-0 -c githubrunner-cs -- docker system prune -f
-c githubrunner-cs: Pod์ ์ปจํ ์ด๋๊ฐ ์ฌ๋ฌ ๊ฐ(์: runner + DinD ์ฌ์ด๋์นด)์ผ ๋ ์ด๋ ์ปจํ ์ด๋์์ ์คํํ ์ง ์ง์ ํฉ๋๋ค. ์๋ตํ๋ฉด ์ฒซ ๋ฒ์งธ ์ปจํ ์ด๋์์ ์คํ๋ฉ๋๋ค.--๋ค๊ฐ ์ปจํ ์ด๋ ์์์ ์ค์ ๋ก ๋๋ฆด ๋ช ๋ น(docker system prune -f)์ ๋๋ค.
Tip: Docker ๋ฐ๋ชฌ์ด ๋ณ๋ ์ฌ์ด๋์นด(์:
dind)์ ์๋ค๋ฉด-c๊ฐ์ ๊ทธ ์ปจํ ์ด๋ ์ด๋ฆ์ผ๋ก ๋ง์ถฐ์ผ ํฉ๋๋ค.kubectl get pod <name> -o jsonpath='{.spec.containers[*].name}'๋ก ์ปจํ ์ด๋ ์ด๋ฆ์ ํ์ธํ์ธ์.
๐๏ธ docker system prune์ ์ ํํ ๋ฌด์์ ์ง์ฐ๋
docker system prune์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฉ์ถ ์ปจํ
์ด๋ยท๋ฏธ์ฌ์ฉ ๋คํธ์ํฌยทdangling ์ด๋ฏธ์งยท๋ฏธ์ฌ์ฉ ๋น๋ ์บ์๋ฅผ ์ญ์ ํ์ง๋ง, ๋ณผ๋ฅจ๊ณผ ํ๊ทธ๊ฐ ๋ถ์ ๋ฏธ์ฌ์ฉ ์ด๋ฏธ์ง๋ ๊ฑด๋๋ฆฌ์ง ์์ต๋๋ค. ์ต์
์ ๋ฐ๋ผ ์ญ์ ๋ฒ์๊ฐ ํฌ๊ฒ ๋ฌ๋ผ์ง๋ฏ๋ก ํ๋ก ์ ๋ฆฌํฉ๋๋ค.
| ๋ช ๋ น | ๋ฉ์ถ ์ปจํ ์ด๋ | dangling ์ด๋ฏธ์ง | ํ๊ทธ๋ ๋ฏธ์ฌ์ฉ ์ด๋ฏธ์ง | ๋น๋ ์บ์ | ๋ณผ๋ฅจ |
|---|---|---|---|---|---|
docker system prune | โ | โ | โ | โ (๋ฏธ์ฌ์ฉ) | โ |
docker system prune -a | โ | โ | โ | โ (์ ์ฒด) | โ |
docker system prune -a --volumes | โ | โ | โ | โ (์ ์ฒด) | โ |
-f/--force: ํ์ธ ํ๋กฌํํธ๋ฅผ ๊ฑด๋๋๋๋ค. ์คํฌ๋ฆฝํธยท์ผ๊ด ์คํ์๋ ํ์์ ๋๋ค.-a/--all: dangling๋ฟ ์๋๋ผ ์ปจํ ์ด๋๊ฐ ์ฐธ์กฐํ์ง ์๋ ๋ชจ๋ ์ด๋ฏธ์ง๋ฅผ ์ญ์ ํฉ๋๋ค. ๋์คํฌ๋ ๋ ํ๋ณด๋์ง๋ง, ๋ค์ ๋น๋์์ ๋ฒ ์ด์ค ์ด๋ฏธ์ง๋ฅผ ๋ค์ ๋ฐ์์ผ ํฉ๋๋ค(์บ์ ์์ค).--volumes: ๋ฏธ์ฌ์ฉ ๋ณผ๋ฅจ๊น์ง ์ญ์ ํฉ๋๋ค. ๋ฐ์ดํฐ ์ ์ค ์ํ์ด ์์ผ๋ runner ์บ์ ๋ณผ๋ฅจ ๊ตฌ์กฐ๋ฅผ ๋ชจ๋ฅด๋ฉด ์ฐ์ง ๋ง์ธ์.
โ ๏ธ runner์์๋ ๋ณดํต
docker system prune -f(๊ธฐ๋ณธ)๊ฐ ์์ ํ ๊ท ํ์ ์ ๋๋ค. ๋์คํฌ๋ฅผ ๋ ๋น์์ผ ํ๋ฉด-a๊น์ง ๊ณ ๋ คํ๋,--volumes๋ ๋ฌด์์ด ์ง์์ง๋์ง ํ์ธ ํ์๋ง ์ฌ์ฉํ์ธ์.
๐ ์ ๋ฆฌ ์ ํ ํ์ธํ๊ธฐ
์ ๋ฆฌ ํจ๊ณผ๋ฅผ ์์น๋ก ํ์ธํ๋ ค๋ฉด docker system df๋ฅผ ํ์ฉํฉ๋๋ค.
1
2
# ํน์ runner Pod์ ๋์คํฌ ์ฌ์ฉ ํํฉ
kubectl exec -n github-runner pod/githubrunner-cs-0 -c githubrunner-cs -- docker system df
1
2
3
4
5
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 42 5 12.3GB 9.8GB (79%)
Containers 8 2 1.2GB 0.9GB (75%)
Local Volumes 15 3 4.1GB 3.0GB (73%)
Build Cache 120 0 6.5GB 6.5GB (100%)
RECLAIMABLE ๊ฐ์ด prune์ผ๋ก ํ์ ๊ฐ๋ฅํ ์ฉ๋์
๋๋ค. ๋
ธ๋ ๋์คํฌ ์์ฒด๋ ๋ค์์ผ๋ก ํ์ธํฉ๋๋ค.
1
2
# ๋
ธ๋ ํ์ผ์์คํ
์ฌ์ฉ๋ฅ
kubectl exec -n github-runner pod/githubrunner-cs-0 -c githubrunner-cs -- df -h /
โฐ CronJob์ผ๋ก ์๋ํํ๊ธฐ
์๋ ์คํ์ ๊น๋จน๊ธฐ ์ฌ์ฐ๋, CronJob์ผ๋ก ์ฃผ๊ธฐ์ ์ ๋ฆฌ๋ฅผ ๊ฑฐ๋ ๊ฒ์ด ์ค๋ฌด์์ ๊ฐ์ฅ ๊น๋ํฉ๋๋ค. ํด๋ฌ์คํฐ ์์์ kubectl์ ์คํํ๋ ค๋ฉด ํด๋น ๋ช
๋ น์ ๋ํ ๊ถํ(RBAC)์ด ํ์ํฉ๋๋ค.
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
# ServiceAccount + RBAC (pods ์กฐํ + exec ๊ถํ)
apiVersion: v1
kind: ServiceAccount
metadata:
name: runner-pruner
namespace: github-runner
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: runner-pruner
namespace: github-runner
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: runner-pruner
namespace: github-runner
subjects:
- kind: ServiceAccount
name: runner-pruner
namespace: github-runner
roleRef:
kind: Role
name: runner-pruner
apiGroup: rbac.authorization.k8s.io
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
# CronJob โ ๋งค์ผ ์๋ฒฝ 4์์ ๋ชจ๋ runner Pod ์ ๋ฆฌ
apiVersion: batch/v1
kind: CronJob
metadata:
name: runner-docker-prune
namespace: github-runner
spec:
schedule: "0 4 * * *" # ๋งค์ผ 04:00 (ํด๋ฌ์คํฐ ํ์์กด ๊ธฐ์ค)
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
serviceAccountName: runner-pruner
restartPolicy: Never
containers:
- name: pruner
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- >
kubectl get -n github-runner pods -l app=githubrunner-cs -o name
| xargs -I {} kubectl exec -n github-runner {} -c githubrunner-cs
-- docker system prune -f
Tip:
schedule์ ํ์์กด์ ๊ธฐ๋ณธ์ ์ผ๋ก kube-controller-manager ๊ธฐ์ค(UTC์ธ ๊ฒฝ์ฐ๊ฐ ๋ง์)์ ๋๋ค. KST ๊ธฐ์ค์ผ๋ก ๋๋ฆฌ๋ ค๋ฉดspec.timeZone: "Asia/Seoul"(Kubernetes 1.27+ ์์ ํ)์ ์ถ๊ฐํ์ธ์.
๐ ํ ์ค ์์ฝ
- self-hosted GitHub Actions runner๋ ํ๊ฒฝ์ด ์ ์ง๋์ด Docker ์ด๋ฏธ์งยท๋น๋ ์บ์๊ฐ ๋์ ๋๋ฏ๋ก ์ฃผ๊ธฐ์ ์ ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
kubectl get -l ... -o name | xargs -I {} kubectl exec ... -- docker system prune -f๋ก ์ฌ๋ฌ runner Pod๋ฅผ ํ ๋ฒ์ ์ ๋ฆฌํ ์ ์์ต๋๋ค.- ๊ธฐ๋ณธ
prune -f๊ฐ ์์ ํ๋ฉฐ,-a(์ ์ฒด ์ด๋ฏธ์ง)ยท--volumes(๋ณผ๋ฅจ)๋ ์ํฅ ๋ฒ์๋ฅผ ์ดํดํ๊ณ ์จ์ผ ํฉ๋๋ค. - ์ด์์์๋ RBAC + CronJob์ผ๋ก ์๋ํํ๋ ๊ฒ์ด ๊ฐ์ฅ ํ์คํฉ๋๋ค.
โ ์์ฃผ ๋ฌป๋ ์ง๋ฌธ
Q. docker system prune -f๋ ์คํ ์ค์ธ ์ปจํ
์ด๋๋ ์ง์ฐ๋์?
์๋๋๋ค. ๋ฉ์ถ(stopped) ์ปจํ ์ด๋, dangling ์ด๋ฏธ์ง, ๋ฏธ์ฌ์ฉ ๋คํธ์ํฌ, ๋ฏธ์ฌ์ฉ ๋น๋ ์บ์๋ง ์ญ์ ํฉ๋๋ค. ์คํ ์ค์ธ ์ปจํ ์ด๋์ ๊ทธ๊ฒ์ด ์ฌ์ฉํ๋ ์ด๋ฏธ์งยท๋ณผ๋ฅจ์ ๋ณด์กด๋ฉ๋๋ค.
Q. -c ์ต์
์ ๊ผญ ์จ์ผ ํ๋์?
Pod์ ์ปจํ
์ด๋๊ฐ ํ๋๋ฉด ์๋ตํด๋ ๋ฉ๋๋ค. runner + DinD ์ฌ์ด๋์นด์ฒ๋ผ ์ฌ๋ฌ ์ปจํ
์ด๋๊ฐ ์์ผ๋ฉด Docker ๋ฐ๋ชฌ์ด ์๋ ์ปจํ
์ด๋๋ฅผ -c๋ก ์ง์ ํด์ผ ํฉ๋๋ค. ์๋ต ์ ์ฒซ ๋ฒ์งธ ์ปจํ
์ด๋์์ ์คํ๋ฉ๋๋ค.
Q. Pod๊ฐ ์์ฃผ ๋ง์ ๋ ํ ๋ฒ์ ๋๋ ค๋ ๋๋์?
xargs๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ฐจ ์คํ์ด๋ผ ์์ ํฉ๋๋ค. ๋ ๋น ๋ฅด๊ฒ ๋ณ๋ ฌ ์คํํ๋ ค๋ฉด xargs -P 4์ฒ๋ผ ๋์ ์คํ ์๋ฅผ ์ง์ ํ ์ ์์ง๋ง, API ์๋ฒยท๋
ธ๋ ๋ถํ๋ฅผ ๊ณ ๋ คํด ์ ๋นํ ์ ํํ์ธ์.
Q. ๋์คํฌ๋ฅผ ๋ ํ๋ณดํ๋ ค๋ฉด -a๋ฅผ ์จ์ผ ํ๋์?
-a๋ ํ๊ทธ๊ฐ ์์ด๋ ์ปจํ
์ด๋๊ฐ ์ฐธ์กฐํ์ง ์๋ ๋ชจ๋ ์ด๋ฏธ์ง๋ฅผ ์ง์๋๋ค. ๋์คํฌ๋ ๋ ๋น์ง๋ง ๋ค์ ๋น๋์์ ๋ฒ ์ด์ค ์ด๋ฏธ์ง๋ฅผ ๋ค์ ๋ฐ์์ผ ํด ๋น๋๊ฐ ๋๋ ค์ง๋๋ค. ์ ๊ธฐ ์ ๋ฆฌ๋ ๊ธฐ๋ณธ prune, ๋์คํฌ ์๊ธฐ ์์๋ง -a๋ฅผ ๊ถ์ฅํฉ๋๋ค.
Q. ARC(Actions Runner Controller)๋ฅผ ์ฐ๋ฉด ์ด๋ป๊ฒ ํ๋์?
ARC์ ephemeral runner๋ ์ก๋ง๋ค Pod๊ฐ ์๋ก ๋ ๋น๊ต์ ๊นจ๋ํ์ง๋ง, DinD ์บ์๋ฅผ ๊ณต์ ๋ณผ๋ฅจ์ ๋๋ ๊ตฌ์ฑ์ด๋ฉด ์ฌ์ ํ ๋์ ๋ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ ๊ณต์ ์บ์ ๋ณผ๋ฅจ์ ๋ํ ์ ๋ฆฌ ์ ์ฑ ์ ๋ณ๋๋ก ๋๊ฑฐ๋ ์ CronJob ๋ฐฉ์์ ์ ์ฉํ์ธ์.
๐ ์ฐธ๊ณ
- Docker Docs - docker system prune
- Docker Docs - Prune unused Docker objects
- Kubernetes Docs - kubectl exec
- Kubernetes Docs - CronJob (timeZone)
- GitHub Docs - About self-hosted runners
- ๊ด๋ จ ๊ธ: Docker Dangling Image๋? ยท kubectl exec command ยท containerd OverlayFS ๋์คํฌ ์ ์ ์ถ์
</content>