๋ชจ๋ฒ” ์‚ฌ๋ก€ ๋ฐ ์ •์ฑ…์„ ๊ธฐ์ค€์œผ๋กœ Kubernetes YAML ๊ฒ€์ฆ

๋ฉ”๋ชจ. ๋ฒˆ์—ญ: K8s ํ™˜๊ฒฝ์— ๋Œ€ํ•œ YAML ๊ตฌ์„ฑ์˜ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•จ์— ๋”ฐ๋ผ ์ž๋™ํ™”๋œ ๊ฒ€์ฆ์˜ ํ•„์š”์„ฑ์ด ์ ์  ๋” ์‹œ๊ธ‰ํ•ด์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฆฌ๋ทฐ์˜ ์ž‘์„ฑ์ž๋Š” ์ด ์ž‘์—…์„ ์œ„ํ•ด ๊ธฐ์กด ์†”๋ฃจ์…˜์„ ์„ ํƒํ–ˆ์„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ฐฐํฌ๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด ์ž‘๋™ ๋ฐฉ์‹์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฃผ์ œ์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ๋ถ„๋“ค์—๊ฒŒ๋Š” ๋งค์šฐ ์œ ์ตํ•œ ๋‚ด์šฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋ฒ” ์‚ฌ๋ก€ ๋ฐ ์ •์ฑ…์„ ๊ธฐ์ค€์œผ๋กœ Kubernetes YAML ๊ฒ€์ฆ

TL; DR: ์ด ๋ฌธ์„œ์—์„œ๋Š” ๋ชจ๋ฒ” ์‚ฌ๋ก€ ๋ฐ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋”ฐ๋ผ Kubernetes YAML ํŒŒ์ผ์„ ๊ฒ€์ฆํ•˜๊ณ  ํ‰๊ฐ€ํ•˜๋Š” XNUMX๊ฐ€์ง€ ์ •์  ๋„๊ตฌ๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

Kubernetes ์›Œํฌ๋กœ๋“œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ YAML ๋ฌธ์„œ ํ˜•์‹์œผ๋กœ ์ •์˜๋ฉ๋‹ˆ๋‹ค. YAML์˜ ๋ฌธ์ œ์  ์ค‘ ํ•˜๋‚˜๋Š” ๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ ๊ฐ„์˜ ์ œ์•ฝ ์กฐ๊ฑด์ด๋‚˜ ๊ด€๊ณ„๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํด๋Ÿฌ์Šคํ„ฐ์— ๋ฐฐํฌ๋œ ๋ชจ๋“  ์ด๋ฏธ์ง€๊ฐ€ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—์„œ ๊ฐ€์ ธ์˜จ ๊ฒƒ์ธ์ง€ ํ™•์ธํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

PodDisruptionBudget์ด ์—†๋Š” ๋ฐฐํฌ๊ฐ€ ํด๋Ÿฌ์Šคํ„ฐ๋กœ ์ „์†ก๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

์ •์  ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ฉํ•˜๋ฉด ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ ์˜ค๋ฅ˜ ๋ฐ ์ •์ฑ… ์œ„๋ฐ˜์„ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฆฌ์†Œ์Šค ์ •์˜๊ฐ€ ์ •ํ™•ํ•˜๊ณ  ์•ˆ์ „ํ•˜๋‹ค๋Š” ๋ณด์žฅ์ด ๊ฐ•ํ™”๋˜๊ณ  ํ”„๋กœ๋•์…˜ ์›Œํฌ๋กœ๋“œ๊ฐ€ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋”ฐ๋ฅผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง‘๋‹ˆ๋‹ค.

Kubernetes ์ •์  YAML ํŒŒ์ผ ๊ฒ€์‚ฌ ์—์ฝ”์‹œ์Šคํ…œ์€ ๋‹ค์Œ ๋ฒ”์ฃผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • API ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ. ์ด ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋„๊ตฌ๋Š” Kubernetes API ์„œ๋ฒ„์˜ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋Œ€ํ•ด YAML ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์ค€๋น„๋œ ํ…Œ์Šคํ„ฐ. ์ด ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋„๊ตฌ์—๋Š” ๋ณด์•ˆ, ๋ชจ๋ฒ” ์‚ฌ๋ก€ ์ค€์ˆ˜ ๋“ฑ์— ๋Œ€ํ•œ ๊ธฐ์„ฑ ํ…Œ์ŠคํŠธ๊ฐ€ ํ•จ๊ป˜ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.
  • ๋งž์ถค ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ. ์ด ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋Œ€ํ‘œ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Rego ๋ฐ Javascript์™€ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์–ธ์–ด๋กœ ์‚ฌ์šฉ์ž ์ •์˜ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ XNUMX๊ฐ€์ง€ ๋„๊ตฌ๋ฅผ ์„ค๋ช…ํ•˜๊ณ  ๋น„๊ตํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  1. ํ๋ธŒ๋ฐœ;
  2. ํ๋ธŒ ์ ์ˆ˜;
  3. ๊ตฌ์„ฑ ๋ฆฐํŠธ;
  4. ๊ตฌ๋ฆฌ;
  5. ์ฝ˜ํ…Œ์ŠคํŠธ;
  6. ํด๋ผ๋ฆฌ์Šค.

์ž, ์‹œ์ž‘ํ•ด ๋ด…์‹œ๋‹ค!

๋ฐฐํฌ ํ™•์ธ

๋„๊ตฌ ๋น„๊ต๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ๋„๊ตฌ๋ฅผ ํ…Œ์ŠคํŠธํ•  ๋ฐฐ๊ฒฝ์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ์„ ์–ธ๋ฌธ์—๋Š” ์ˆ˜๋งŽ์€ ์˜ค๋ฅ˜์™€ ๋ชจ๋ฒ” ์‚ฌ๋ก€ ๋ฏธ์ค€์ˆ˜๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ๋ช‡ ๊ฐœ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‚˜์š”?

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: http-echo
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: http-echo
spec:
  ports:
  - port: 5678
    protocol: TCP
    targetPort: 5678
  selector:
    app: http-echo

(base-valid.yaml)

์ด YAML์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๋„๊ตฌ๋ฅผ ๋น„๊ตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์„ ์–ธ๋ฌธ base-valid.yaml ์ด ๊ธฐ์‚ฌ์˜ ๋‹ค๋ฅธ ์„ ์–ธ๋ฌธ์€ ๋‹ค์Œ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํž˜๋‚ด ์ €์žฅ์†Œ.

๋งค๋‹ˆํŽ˜์ŠคํŠธ๋Š” ํฌํŠธ 5678์— "Hello World" ๋ฉ”์‹œ์ง€๋กœ ์‘๋‹ตํ•˜๋Š” ๊ฒƒ์ด ์ฃผ์š” ์ž‘์—…์ธ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

kubectl apply -f hello-world.yaml

๊ทธ๋ž˜์„œ - ์ž‘์—…์„ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค :

kubectl port-forward svc/http-echo 8080:5678

์ด์ œ ์ด๋™ http://localhost:8080 ๊ทธ๋ฆฌ๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ํ•˜์ง€๋งŒ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋”ฐ๋ฅด๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ์ ๊ฒ€ ํ•ด๋ณด์ž.

1. ํ๋ธŒ๋ฐœ

์ค‘์‹ฌ ํ๋ธŒ๋ฐœ Kubernetes์™€์˜ ๋ชจ๋“  ์ƒํ˜ธ ์ž‘์šฉ์€ REST API๋ฅผ ํ†ตํ•ด ๋ฐœ์ƒํ•œ๋‹ค๋Š” ์•„์ด๋””์–ด์ž…๋‹ˆ๋‹ค. ์ฆ‰, API ์Šคํ‚ค๋งˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฃผ์–ด์ง„ YAML์ด ์ด๋ฅผ ์ค€์ˆ˜ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์„ค์น˜ ์ง€์นจ kubeval์€ ํ”„๋กœ์ ํŠธ ์›น์‚ฌ์ดํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์›๋ณธ ๊ธฐ์‚ฌ๋ฅผ ์ž‘์„ฑํ•  ๋‹น์‹œ์—๋Š” ๋ฒ„์ „ 0.15.0์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์„ค์น˜๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์œ„์˜ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

$ kubeval base-valid.yaml
PASS - base-valid.yaml contains a valid Deployment (http-echo)
PASS - base-valid.yaml contains a valid Service (http-echo)

์„ฑ๊ณตํ•˜๋ฉด kubeval์€ ์ข…๋ฃŒ ์ฝ”๋“œ 0์œผ๋กœ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ echo $?
0

์ด์ œ ๋‹ค๋ฅธ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ kubeval์„ ์‹œ๋„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: http-echo
spec:
  ports:
  - port: 5678
    protocol: TCP
    targetPort: 5678
  selector:
    app: http-echo

(kubeval-invalid.yaml)

๋ˆˆ์œผ๋กœ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋‚˜์š”? ์‹œ์ž‘ํ•ด๋ณด์ž:

$ kubeval kubeval-invalid.yaml
WARN - kubeval-invalid.yaml contains an invalid Deployment (http-echo) - selector: selector is required
PASS - kubeval-invalid.yaml contains a valid Service (http-echo)

# ะฟั€ะพะฒะตั€ะธะผ ะบะพะด ะฒะพะทะฒั€ะฐั‚ะฐ
$ echo $?
1

๋ฆฌ์†Œ์Šค๊ฐ€ ํ™•์ธ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

API ๋ฒ„์ „์„ ์‚ฌ์šฉํ•œ ๋ฐฐํฌ apps/v1, ํฌ๋“œ ๋ผ๋ฒจ๊ณผ ์ผ์น˜ํ•˜๋Š” ์„ ํƒ๊ธฐ๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์œ„์˜ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—๋Š” ์„ ํƒ๊ธฐ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ kubeval์€ ์˜ค๋ฅ˜๋ฅผ ๋ณด๊ณ ํ•˜๊ณ  XNUMX์ด ์•„๋‹Œ ์ฝ”๋“œ๋กœ ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ์ง€ ๊ถ๊ธˆํ•ด์š” kubectl apply -f ์ด ์„ ์–ธ๋ฌธ์œผ๋กœ?

์Œ, ์‹œ๋„ํ•ด ๋ด…์‹œ๋‹ค:

$ kubectl apply -f kubeval-invalid.yaml
error: error validating "kubeval-invalid.yaml": error validating data: ValidationError(Deployment.spec):
missing required field "selector" in io.k8s.api.apps.v1.DeploymentSpec; if you choose to ignore these errors,
turn validation off with --validate=false

์ด๊ฒƒ์ด ๋ฐ”๋กœ kubeval์ด ๊ฒฝ๊ณ ํ•œ ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค. ์„ ํƒ๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  selector:          # !!!
    matchLabels:     # !!!
      app: http-echo # !!!
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: http-echo
spec:
  ports:
  - port: 5678
    protocol: TCP
    targetPort: 5678
  selector:
    app: http-echo

(base-valid.yaml)

kubeval๊ณผ ๊ฐ™์€ ๋„๊ตฌ์˜ ์ด์ ์€ ๋ฐฐํฌ ์ฃผ๊ธฐ ์ดˆ๊ธฐ์— ์ด์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๋ฅผ ํฌ์ฐฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ์ด๋Ÿฌํ•œ ๊ฒ€์‚ฌ์—๋Š” ํด๋Ÿฌ์Šคํ„ฐ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉฐ ์˜คํ”„๋ผ์ธ์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ kubeval์€ ์ตœ์‹  Kubernetes API ์Šคํ‚ค๋งˆ์— ๋Œ€ํ•ด ๋ฆฌ์†Œ์Šค๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ํŠน์ • Kubernetes ๋ฆด๋ฆฌ์Šค๋ฅผ ํ™•์ธํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. --kubernetes-version:

$ kubeval --kubernetes-version 1.16.1 base-valid.yaml

๋ฒ„์ „์€ ๋‹ค์Œ ํ˜•์‹์œผ๋กœ ์ง€์ •๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Major.Minor.Patch.

๊ฒ€์ฆ์ด ์ง€์›๋˜๋Š” ๋ฒ„์ „ ๋ชฉ๋ก์€ ๋‹ค์Œ์„ ์ฐธ์กฐํ•˜์„ธ์š”. GitHub์˜ JSON ์Šคํ‚ค๋งˆ, kubeval์ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. kubeval์„ ์˜คํ”„๋ผ์ธ์œผ๋กœ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์Šคํ‚ค๋งˆ๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ์ปฌ ์œ„์น˜๋ฅผ ์ง€์ •ํ•˜์„ธ์š”. --schema-location.

๊ฐœ๋ณ„ YAML ํŒŒ์ผ ์™ธ์—๋„ kubeval์€ ๋””๋ ‰ํ„ฐ๋ฆฌ ๋ฐ stdin์—์„œ๋„ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ Kubeval์€ CI ํŒŒ์ดํ”„๋ผ์ธ์— ์‰ฝ๊ฒŒ ํ†ตํ•ฉ๋ฉ๋‹ˆ๋‹ค. ํด๋Ÿฌ์Šคํ„ฐ์— ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๋ณด๋‚ด๊ธฐ ์ „์— ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ kubeval์ด ์„ธ ๊ฐ€์ง€ ์ถœ๋ ฅ ํ˜•์‹์„ ์ง€์›ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๊ฒŒ ๋˜๋ฉด ๊ธฐ๋ปํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  1. ์ผ๋ฐ˜ ํ…์ŠคํŠธ;
  2. JSON;
  3. TAP(๋ฌด์—‡์ด๋“  ํ…Œ์ŠคํŠธ ํ”„๋กœํ† ์ฝœ).

๊ทธ๋ฆฌ๊ณ  ์›ํ•˜๋Š” ์œ ํ˜•์˜ ๊ฒฐ๊ณผ ์š”์•ฝ์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์ถœ๋ ฅ์„ ์ถ”๊ฐ€๋กœ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๋Š” ๋ฐ ๋ชจ๋“  ํ˜•์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

kubeval์˜ ๋‹จ์  ์ค‘ ํ•˜๋‚˜๋Š” ํ˜„์žฌ CRD(์‚ฌ์šฉ์ž ์ •์˜ ๋ฆฌ์†Œ์Šค ์ •์˜) ์ค€์ˆ˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ kubeval์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋“ค์„ ๋ฌด์‹œํ•˜๋ผ.

Kubeval์€ ๋ฆฌ์†Œ์Šค๋ฅผ ํ™•์ธํ•˜๊ณ  ํ‰๊ฐ€ํ•˜๋Š” ํ›Œ๋ฅญํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•œ๋‹ค๊ณ  ํ•ด์„œ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์ค€์ˆ˜ํ•œ๋‹ค๊ณ  ๋ณด์žฅ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ผ๋Š” ์ ์„ ๊ฐ•์กฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด latest ์ปจํ…Œ์ด๋„ˆ์—์„œ๋Š” ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋”ฐ๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ kubeval์€ ์ด๋ฅผ ์˜ค๋ฅ˜๋กœ ๊ฐ„์ฃผํ•˜์ง€ ์•Š์œผ๋ฉฐ ์ด๋ฅผ ๋ณด๊ณ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰, ํ•ด๋‹น YAML์˜ ํ™•์ธ์€ ๊ฒฝ๊ณ  ์—†์ด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ YAML์„ ํ‰๊ฐ€ํ•˜๊ณ  ํƒœ๊ทธ์™€ ๊ฐ™์€ ์œ„๋ฐ˜์„ ์‹๋ณ„ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”? latest? ๋ชจ๋ฒ” ์‚ฌ๋ก€์™€ ๋น„๊ตํ•˜์—ฌ YAML ํŒŒ์ผ์„ ํ™•์ธํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

2. ํ๋ธŒ ์ ์ˆ˜

ํ๋ธŒ ์ ์ˆ˜ YAML ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ณ  ๋‚ด์žฅ ํ…Œ์ŠคํŠธ์™€ ๋น„๊ตํ•˜์—ฌ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ณด์•ˆ ์ง€์นจ ๋ฐ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ ํƒ๋ฉ๋‹ˆ๋‹ค.

  • ๋ฃจํŠธ๊ฐ€ ์•„๋‹Œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ํฌ๋“œ ์ƒํƒœ ํ™•์ธ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์š”์ฒญ ๋ฐ ์ œํ•œ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ์„ธ ๊ฐ€์ง€ ๊ฒฐ๊ณผ๊ฐ€ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. OK, ๊ฒฝ๊ณ  ะธ ๊ฒฐ์ •์ ์ธ.

Kube-score๋ฅผ ์˜จ๋ผ์ธ์œผ๋กœ ์‚ฌ์šฉํ•ด ๋ณด๊ฑฐ๋‚˜ ๋กœ์ปฌ๋กœ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์›๋ฌธ์„ ์ž‘์„ฑํ•  ๋‹น์‹œ kube-score์˜ ์ตœ์‹  ๋ฒ„์ „์€ 1.7.0์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋งค๋‹ˆํŽ˜์ŠคํŠธ์—์„œ ์‹œ๋„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. base-valid.yaml:

$ kube-score score base-valid.yaml

apps/v1/Deployment http-echo
[CRITICAL] Container Image Tag
  ยท http-echo -> Image with latest tag
      Using a fixed tag is recommended to avoid accidental upgrades
[CRITICAL] Pod NetworkPolicy
  ยท The pod does not have a matching network policy
      Create a NetworkPolicy that targets this pod
[CRITICAL] Pod Probes
  ยท Container is missing a readinessProbe
      A readinessProbe should be used to indicate when the service is ready to receive traffic.
      Without it, the Pod is risking to receive traffic before it has booted. It is also used during
      rollouts, and can prevent downtime if a new version of the application is failing.
      More information: https://github.com/zegl/kube-score/blob/master/README_PROBES.md
[CRITICAL] Container Security Context
  ยท http-echo -> Container has no configured security context
      Set securityContext to run the container in a more secure context.
[CRITICAL] Container Resources
  ยท http-echo -> CPU limit is not set
      Resource limits are recommended to avoid resource DDOS. Set resources.limits.cpu
  ยท http-echo -> Memory limit is not set
      Resource limits are recommended to avoid resource DDOS. Set resources.limits.memory
  ยท http-echo -> CPU request is not set
      Resource requests are recommended to make sure that the application can start and run without
      crashing. Set resources.requests.cpu
  ยท http-echo -> Memory request is not set
      Resource requests are recommended to make sure that the application can start and run without crashing.
      Set resources.requests.memory
[CRITICAL] Deployment has PodDisruptionBudget
  ยท No matching PodDisruptionBudget was found
      It is recommended to define a PodDisruptionBudget to avoid unexpected downtime during Kubernetes
      maintenance operations, such as when draining a node.
[WARNING] Deployment has host PodAntiAffinity
  ยท Deployment does not have a host podAntiAffinity set
      It is recommended to set a podAntiAffinity that stops multiple pods from a deployment from
      being scheduled on the same node. This increases availability in case the node becomes unavailable.

YAML์€ kubeval ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•œ ๋ฐ˜๋ฉด kube-score๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐํ•จ์„ ์ง€์ ํ•ฉ๋‹ˆ๋‹ค.

  • ์ค€๋น„ ํ™•์ธ์ด ๊ตฌ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
  • CPU ๋ฆฌ์†Œ์Šค ๋ฐ ๋ฉ”๋ชจ๋ฆฌ์— ๋Œ€ํ•œ ์š”์ฒญ์ด๋‚˜ ์ œํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ํฌ๋“œ ์ค‘๋‹จ ์˜ˆ์‚ฐ์ด ์ง€์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
  • ์ด๋ณ„์˜ ๋ฒ•์น™์€ ์—†๋‹ค (๋ฐ˜์นœํ™”์„ฑ) ๊ฐ€์šฉ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ๋Š” ๋ฃจํŠธ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์ด๋Š” ๋ชจ๋‘ ๋ฐฐํฌ๋ฅผ ๋ณด๋‹ค ํšจ์œจ์ ์ด๊ณ  ์•ˆ์ •์ ์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๋‹จ์ ์— ๋Œ€ํ•œ ์œ ํšจํ•œ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

ํŒ€ kube-score ๋ชจ๋“  ์œ ํ˜• ์œ„๋ฐ˜์„ ํฌํ•จํ•˜์—ฌ ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ํ˜•์‹์œผ๋กœ ์ •๋ณด๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๊ฒฝ๊ณ  ะธ ๊ฒฐ์ •์ ์ธ, ๊ฐœ๋ฐœ ์ค‘์— ๋งŽ์€ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

CI ํŒŒ์ดํ”„๋ผ์ธ ๋‚ด์—์„œ ์ด ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋” ์••์ถ•๋œ ์ถœ๋ ฅ์„ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. --output-format ci (์ด ๊ฒฝ์šฐ ๊ฒฐ๊ณผ๊ฐ€ ํฌํ•จ๋œ ํ…Œ์ŠคํŠธ๋„ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. OK):

$ kube-score score base-valid.yaml --output-format ci

[OK] http-echo apps/v1/Deployment
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) CPU limit is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Memory limit is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) CPU request is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Memory request is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Image with latest tag
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: The pod does not have a matching network policy
[CRITICAL] http-echo apps/v1/Deployment: Container is missing a readinessProbe
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Container has no configured security context
[CRITICAL] http-echo apps/v1/Deployment: No matching PodDisruptionBudget was found
[WARNING] http-echo apps/v1/Deployment: Deployment does not have a host podAntiAffinity set
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service

kubeval๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ, kube-score๋Š” ์‹คํŒจํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ XNUMX์ด ์•„๋‹Œ ์ข…๋ฃŒ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ์ •์ ์ธ. ๋‹ค์Œ์— ๋Œ€ํ•ด ์œ ์‚ฌํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ™œ์„ฑํ™”ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒฝ๊ณ .

๋˜ํ•œ kubeval์—์„œ์™€ ๊ฐ™์ด ๋ฆฌ์†Œ์Šค๊ฐ€ ๋‹ค์–‘ํ•œ API ๋ฒ„์ „์„ ์ค€์ˆ˜ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ์ •๋ณด๋Š” kube-score ์ž์ฒด์— ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ๋‹ค๋ฅธ ๋ฒ„์ „์˜ Kubernetes๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ๋˜๋Š” K8 ๋ฒ„์ „์ด ์„œ๋กœ ๋‹ค๋ฅธ ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋Ÿฌํ•œ ์ œํ•œ์€ ํฐ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ  ์ด๋ฏธ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด ์ด ๊ธฐํšŒ๋ฅผ ์‹คํ˜„ํ•˜์ž๋Š” ์ œ์•ˆ์œผ๋กœ.

kube-score์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณต์‹ ์›น ์‚ฌ์ดํŠธ.

Kube-score ํ…Œ์ŠคํŠธ๋Š” ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ํ›Œ๋ฅญํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ…Œ์ŠคํŠธ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์ž์ฒด ๊ทœ์น™์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”? ์•„์‰ฝ๊ฒŒ๋„ ์ด๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Kube-score๋Š” ํ™•์žฅ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ •์ฑ…์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์กฐ์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํšŒ์‚ฌ ์ •์ฑ… ์ค€์ˆ˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž ์ •์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ config-lint, Copper, conftest ๋˜๋Š” polaris์˜ ๋„ค ๊ฐ€์ง€ ๋„๊ตฌ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3.๊ตฌ์„ฑ ๋ฆฐํŠธ

Config-lint๋Š” YAML, JSON, Terraform, CSV ๊ตฌ์„ฑ ํŒŒ์ผ ๋ฐ Kubernetes ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€์นจ ํ”„๋กœ์ ํŠธ ์›น์‚ฌ์ดํŠธ์—์„œ.

์›๋ณธ ๊ธฐ์‚ฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์‹œ์ ์˜ ํ˜„์žฌ ๋ฆด๋ฆฌ์Šค๋Š” 1.5.0์ž…๋‹ˆ๋‹ค.

Config-lint์—๋Š” Kubernetes ๋งค๋‹ˆํŽ˜์ŠคํŠธ ๊ฒ€์ฆ์„ ์œ„ํ•œ ๋‚ด์žฅ ํ…Œ์ŠคํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ์ ์ ˆํ•œ ๊ทœ์น™์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. "ruleset"์ด๋ผ๋Š” YAML ํŒŒ์ผ๋กœ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค. (๊ทœ์น™ ์„ธํŠธ)์ด๋ฉฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.

version: 1
description: Rules for Kubernetes spec files
type: Kubernetes
files:
  - "*.yaml"
rules:
   # ัะฟะธัะพะบ ะฟั€ะฐะฒะธะป

(rule.yaml)

์ข€ ๋” ์ž์„ธํžˆ ์—ฐ๊ตฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ๋ถ„์•ผ type config-lint๊ฐ€ ์‚ฌ์šฉํ•  ๊ตฌ์„ฑ ์œ ํ˜•์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. K8์˜ ๊ฒฝ์šฐ ์ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ•ญ์ƒ Kubernetes.
  • ํ˜„์žฅ์—์„œ files ํŒŒ์ผ ์ž์ฒด ์™ธ์—๋„ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ถ„์•ผ rules ์‚ฌ์šฉ์ž ํ…Œ์ŠคํŠธ๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐฐํฌ์˜ ์ด๋ฏธ์ง€๊ฐ€ ํ•ญ์ƒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ €์žฅ์†Œ์—์„œ ๋‹ค์šด๋กœ๋“œ๋˜๋„๋ก ํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. my-company.com/myapp:1.0. ์ด๋Ÿฌํ•œ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” config-lint ๊ทœ์น™์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

- id: MY_DEPLOYMENT_IMAGE_TAG
  severity: FAILURE
  message: Deployment must use a valid image tag
  resource: Deployment
  assertions:
    - every:
        key: spec.template.spec.containers
        expressions:
          - key: image
            op: starts-with
            value: "my-company.com/"

(rule-trusted-repo.yaml)

๊ฐ ๊ทœ์น™์—๋Š” ๋‹ค์Œ ์†์„ฑ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • id - ๊ทœ์น™์˜ ๊ณ ์œ  ์‹๋ณ„์ž
  • severity - ์•„๋งˆ๋„ ๊ณ ์žฅ ๋ถ„์„, ๊ฒฝ๊ณ  ะธ ๋น„์ค€์ˆ˜;
  • message โ€” ๊ทœ์น™์„ ์œ„๋ฐ˜ํ•˜๋ฉด ์ด ์ค„์˜ ๋‚ด์šฉ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  • resource โ€” ์ด ๊ทœ์น™์ด ์ ์šฉ๋˜๋Š” ์ž์›์˜ ์œ ํ˜•
  • assertions โ€” ์ด ๋ฆฌ์†Œ์Šค์™€ ๊ด€๋ จํ•˜์—ฌ ํ‰๊ฐ€๋  ์กฐ๊ฑด ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค.

์œ„์˜ ๊ทœ์น™์—์„œ assertion ์ž๊ฒฉ every ๋ชจ๋“  ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋ฐฐํฌ ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค(key: spec.templates.spec.containers) ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: my-company.com/).

์ „์ฒด ๊ทœ์น™ ์„ธํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

version: 1
description: Rules for Kubernetes spec files
type: Kubernetes
files:
  - "*.yaml"
rules:

 - id: DEPLOYMENT_IMAGE_REPOSITORY # !!!
    severity: FAILURE
    message: Deployment must use a valid image repository
    resource: Deployment
    assertions:
      - every:
          key: spec.template.spec.containers
          expressions:
            - key: image
              op: starts-with
              value: "my-company.com/"

(ruleset.yaml)

ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ์ด๋ฆ„์œผ๋กœ ์ €์žฅํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. check_image_repo.yaml. ํŒŒ์ผ์„ ๊ฒ€์‚ฌํ•ด๋ณด์ž base-valid.yaml:

$ config-lint -rules check_image_repo.yaml base-valid.yaml

[
  {
  "AssertionMessage": "Every expression fails: And expression fails: image does not start with my-company.com/",
  "Category": "",
  "CreatedAt": "2020-06-04T01:29:25Z",
  "Filename": "test-data/base-valid.yaml",
  "LineNumber": 0,
  "ResourceID": "http-echo",
  "ResourceType": "Deployment",
  "RuleID": "DEPLOYMENT_IMAGE_REPOSITORY",
  "RuleMessage": "Deployment must use a valid image repository",
  "Status": "FAILURE"
  }
]

ํ™•์ธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์˜ฌ๋ฐ”๋ฅธ ์ด๋ฏธ์ง€ ์ €์žฅ์†Œ๊ฐ€ ํฌํ•จ๋œ ๋‹ค์Œ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: http-echo
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
         image: my-company.com/http-echo:1.0 # !!!
         args: ["-text", "hello-world"]
         ports:
         - containerPort: 5678

(image-valid-mycompany.yaml)

์œ„์˜ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋ฐœ๊ฒฌ๋œ ๋ฌธ์ œ ์—†์Œ:

$ config-lint -rules check_image_repo.yaml image-valid-mycompany.yaml
[]

Config-lint๋Š” YAML DSL์„ ์‚ฌ์šฉํ•˜์—ฌ Kubernetes YAML ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•œ ์ž์ฒด ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ์œ ๋งํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋” ๋ณต์žกํ•œ ๋กœ์ง๊ณผ ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? YAML์€ ์ด์— ๋น„ํ•ด ๋„ˆ๋ฌด ์ œํ•œ์ ์ด์ง€ ์•Š๋‚˜์š”? ์™„์ „ํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋ฉด ์–ด๋–จ๊นŒ์š”?

4. ๊ตฌ๋ฆฌ

๊ตฌ๋ฆฌ V2 ์‚ฌ์šฉ์ž ์ •์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค(config-lint์™€ ์œ ์‚ฌ).

๊ทธ๋Ÿฌ๋‚˜ ํ…Œ์ŠคํŠธ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด YAML์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์—์„œ ํ›„์ž์™€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋Œ€์‹  JavaScript๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Copper๋Š” ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋ณธ ๋„๊ตฌ๊ฐ€ ํฌํ•จ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค., Kubernetes ๊ฐœ์ฒด์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ฝ๊ณ  ์˜ค๋ฅ˜๋ฅผ ๋ณด๊ณ ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

Copper ์„ค์น˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณต์‹ ๋ฌธ์„œ.

2.0.1์€ ์›๋ณธ ๊ธฐ์‚ฌ๋ฅผ ์ž‘์„ฑํ•  ๋‹น์‹œ ์ด ์œ ํ‹ธ๋ฆฌํ‹ฐ์˜ ์ตœ์‹  ๋ฆด๋ฆฌ์Šค์ž…๋‹ˆ๋‹ค.

config-lint์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Copper์—๋Š” ๋‚ด์žฅ ํ…Œ์ŠคํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜ ์จ๋ณด์ž. ๋ฐฐํฌ ์‹œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ €์žฅ์†Œ์˜ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋งŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. my-company.com.

ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ check_image_repo.js ๋‹ค์Œ ๋‚ด์šฉ์œผ๋กœ:

$$.forEach(function($){
    if ($.kind === 'Deployment') {
        $.spec.template.spec.containers.forEach(function(container) {
            var image = new DockerImage(container.image);
            if (image.registry.lastIndexOf('my-company.com/') != 0) {
                errors.add_error('no_company_repo',"Image " + $.metadata.name + " is not from my-company.com repo", 1)
            }
        });
    }
});

์ด์ œ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ํ…Œ์ŠคํŠธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. base-valid.yaml, ๋ช…๋ น์„ ์‚ฌ์šฉ copper validate:

$ copper validate --in=base-valid.yaml --validator=check_image_tag.js

Check no_company_repo failed with severity 1 due to Image http-echo is not from my-company.com repo
Validation failed

Copper์˜ ๋„์›€์œผ๋กœ Ingress ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—์„œ ๋„๋ฉ”์ธ ์ด๋ฆ„์„ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ๊ถŒํ•œ ์žˆ๋Š” ๋ชจ๋“œ์—์„œ ์‹คํ–‰๋˜๋Š” ํฌ๋“œ๋ฅผ ๊ฑฐ๋ถ€ํ•˜๋Š” ๋“ฑ ๋” ๋ณต์žกํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

Copper์—๋Š” ๋‹ค์–‘ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๊ธฐ๋Šฅ์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • DockerImage ์ง€์ •๋œ ์ž…๋ ฅ ํŒŒ์ผ์„ ์ฝ๊ณ  ๋‹ค์Œ ์†์„ฑ์„ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    • name - ์ด๋ฏธ์ง€ ์ด๋ฆ„,
    • tag - ์ด๋ฏธ์ง€ ํƒœ๊ทธ,
    • registry - ์ด๋ฏธ์ง€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ,
    • registry_url - ๊ทœ์•ฝ (https://) ๋ฐ ์ด๋ฏธ์ง€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ,
    • fqin โ€” ์ด๋ฏธ์ง€์˜ ์ „์ฒด ์œ„์น˜.
  • ๊ธฐ๋Šฅ findByName ํŠน์ • ์œ ํ˜•์œผ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค(kind) ๋ฐ ์ด๋ฆ„(name) ์ž…๋ ฅ ํŒŒ์ผ์—์„œ.
  • ๊ธฐ๋Šฅ findByLabels ์ง€์ •๋œ ์œ ํ˜•์œผ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค(kind) ๋ฐ ๋ผ๋ฒจ(labels).

์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์„œ๋น„์Šค ๊ธฐ๋Šฅ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—.

๊ธฐ๋ณธ์ ์œผ๋กœ ์ „์ฒด ์ž…๋ ฅ YAML ํŒŒ์ผ์„ ๋ณ€์ˆ˜๋กœ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. $$ ์Šคํฌ๋ฆฝํŒ…(jQuery ๊ฒฝํ—˜์ด ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์นœ์ˆ™ํ•œ ๊ธฐ์ˆ )์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Copper์˜ ์ฃผ์š” ์žฅ์ ์€ ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ „๋ฌธ ์–ธ์–ด๋ฅผ ๋งˆ์Šคํ„ฐํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ๋‹ค์–‘ํ•œ JavaScript ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด ๋ณด๊ฐ„, ํ•จ์ˆ˜ ๋“ฑ๊ณผ ๊ฐ™์€ ์ž์‹ ๋งŒ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ํ˜„์žฌ ๋ฒ„์ „์˜ Copper๋Š” ES5์ด ์•„๋‹Œ ES6 ๋ฒ„์ „์˜ JavaScript ์—”์ง„์—์„œ ์ž‘๋™ํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ ๊ณต์‹ ํ™ˆํŽ˜์ด์ง€.

๊ทธ๋Ÿฌ๋‚˜ JavaScript๋ฅผ ๋ณ„๋กœ ์ข‹์•„ํ•˜์ง€ ์•Š๊ณ  ์ฟผ๋ฆฌ ์ƒ์„ฑ ๋ฐ ์ •์ฑ… ์„ค๋ช…์„ ์œ„ํ•ด ํŠน๋ณ„ํžˆ ์„ค๊ณ„๋œ ์–ธ์–ด๋ฅผ ์„ ํ˜ธํ•œ๋‹ค๋ฉด conftest์— ์ฃผ์˜๋ฅผ ๊ธฐ์šธ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

5.๋Œ€ํšŒ

Conftest๋Š” ๊ตฌ์„ฑ ๋ฐ์ดํ„ฐ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. Kubernetes ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ํ…Œ์ŠคํŠธ/๊ฒ€์ฆํ•˜๋Š” ๋ฐ์—๋„ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋Š” ํŠน์ˆ˜ ์ฟผ๋ฆฌ ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค. ๋ ˆ๊ณ .

๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ conftest๋ฅผ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€์นจํ”„๋กœ์ ํŠธ ์›น์‚ฌ์ดํŠธ์— ๊ธฐ์žฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์›๋ณธ ๊ธฐ์‚ฌ๋ฅผ ์ž‘์„ฑํ•  ๋‹น์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ตœ์‹  ๋ฒ„์ „์€ 0.18.2์˜€์Šต๋‹ˆ๋‹ค.

config-lint ๋ฐ Copper์™€ ์œ ์‚ฌํ•˜๊ฒŒ conftest๋Š” ๋‚ด์žฅ ํ…Œ์ŠคํŠธ ์—†์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์‹œํ—˜ํ•ด๋ณด๊ณ  ์ž์ฒด ์ •์ฑ…์„ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด์ „ ์˜ˆ์‹œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๊ฐ€ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์†Œ์Šค์—์„œ ๊ฐ€์ ธ์˜จ ๊ฒƒ์ธ์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋””๋ ‰ํ„ฐ๋ฆฌ ์ƒ์„ฑ conftest-checks, ๊ทธ ์•ˆ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. check_image_registry.rego ๋‹ค์Œ ๋‚ด์šฉ์œผ๋กœ:

package main

deny[msg] {

  input.kind == "Deployment"
  image := input.spec.template.spec.containers[_].image
  not startswith(image, "my-company.com/")
  msg := sprintf("image '%v' doesn't come from my-company.com repository", [image])
}

์ด์ œ ํ…Œ์ŠคํŠธํ•ด๋ณด์ž base-valid.yaml ๋ฅผ ํ†ตํ•ด conftest:

$ conftest test --policy ./conftest-checks base-valid.yaml

FAIL - base-valid.yaml - image 'hashicorp/http-echo' doesn't come from my-company.com repository
1 tests, 1 passed, 0 warnings, 1 failure

์ด๋ฏธ์ง€๊ฐ€ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์†Œ์Šค์—์„œ ์™”๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์ƒ๋Œ€๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.

Rego ํŒŒ์ผ์—์„œ ๋ธ”๋ก์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. deny. ๊ทธ ์ง„์‹ค์€ ์œ„๋ฐ˜์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค. ์ฐจ๋‹จํ•˜๋ฉด deny ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ปจํ…Œ์ŠคํŠธ๋Š” ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์ด๋ฅผ ํ™•์ธํ•˜๋ฉฐ, ๋ธ”๋ก ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ง„์‹ค์ด๋ฉด ์œ„๋ฐ˜์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์ถœ๋ ฅ ์™ธ์—๋„ conftest๋Š” JSON, TAP ๋ฐ ํ…Œ์ด๋ธ” ํ˜•์‹์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ธฐ์กด CI ํŒŒ์ดํ”„๋ผ์ธ์— ๋ณด๊ณ ์„œ๋ฅผ ํฌํ•จํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋งค์šฐ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” ํ˜•์‹์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค --output.

์ •์ฑ… ๋””๋ฒ„๊น…์„ ๋” ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด conftest์—๋Š” ํ”Œ๋ž˜๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. --trace. conftest๊ฐ€ ์ง€์ •๋œ ์ •์ฑ… ํŒŒ์ผ์„ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ถ”์ ์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

์ฝ˜ํ…Œ์ŠคํŠธ ์ •์ฑ…์€ OCI(Open Container Initiative) ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์•„ํ‹ฐํŒฉํŠธ๋กœ ๊ฒŒ์‹œ ๋ฐ ๊ณต์œ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŒ€ push ะธ pull ์•„ํ‹ฐํŒฉํŠธ๋ฅผ ๊ฒŒ์‹œํ•˜๊ฑฐ๋‚˜ ์›๊ฒฉ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—์„œ ๊ธฐ์กด ์•„ํ‹ฐํŒฉํŠธ๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ์ปฌ Docker ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์ƒ์„ฑํ•œ ์ •์ฑ…์„ ๊ฒŒ์‹œํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. conftest push.

๋กœ์ปฌ Docker ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

$ docker run -it --rm -p 5000:5000 registry

๋‹ค๋ฅธ ํ„ฐ๋ฏธ๋„์—์„œ ์ด์ „์— ์ƒ์„ฑํ•œ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. conftest-checks ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์‹ญ์‹œ์˜ค.

$ conftest push 127.0.0.1:5000/amitsaha/opa-bundle-example:latest

๋ช…๋ น์ด ์„ฑ๊ณตํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

2020/06/10 14:25:43 pushed bundle with digest: sha256:e9765f201364c1a8a182ca637bc88201db3417bacc091e7ef8211f6c2fd2609c

์ด์ œ ์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ ์•ˆ์—์„œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์‹ญ์‹œ์˜ค. conftest pull. ์ด์ „ ๋ช…๋ น์œผ๋กœ ์ƒ์„ฑ๋œ ํŒจํ‚ค์ง€๋ฅผ ๋‹ค์šด๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

$ cd $(mktemp -d)
$ conftest pull 127.0.0.1:5000/amitsaha/opa-bundle-example:latest

์ž„์‹œ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ํ•˜์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. policy์ •์ฑ… ํŒŒ์ผ์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:

$ tree
.
โ””โ”€โ”€ policy
  โ””โ”€โ”€ check_image_registry.rego

ํ…Œ์ŠคํŠธ๋Š” ์ €์žฅ์†Œ์—์„œ ์ง์ ‘ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ conftest test --update 127.0.0.1:5000/amitsaha/opa-bundle-example:latest base-valid.yaml
..
FAIL - base-valid.yaml - image 'hashicorp/http-echo' doesn't come from my-company.com repository
2 tests, 1 passed, 0 warnings, 1 failure

์•ˆํƒ€๊น๊ฒŒ๋„ DockerHub๋Š” ์•„์ง ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์‚ฌ์šฉํ•˜๋ฉด ์šด์ด ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹ญ์‹œ์˜ค. Azure ์ปจํ…Œ์ด๋„ˆ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ (ACR) ๋˜๋Š” ์ž์ฒด ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ.

์•„ํ‹ฐํŒฉํŠธ ํ˜•์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐฉํ˜• ์ •์ฑ… ์—์ด์ „ํŠธ ํŒจํ‚ค์ง€ (OPA) - conftest๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ์กด OPA ํŒจํ‚ค์ง€์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ •์ฑ… ๊ณต์œ  ๋ฐ ๊ธฐํƒ€ ์ปจํ…Œ์ŠคํŠธ ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ ๊ณต์‹ ํ™ˆํŽ˜์ด์ง€.

6. ํด๋ผ๋ฆฌ์Šค

์ด ๊ธฐ์‚ฌ์—์„œ ๋…ผ์˜ํ•  ๋งˆ์ง€๋ง‰ ๋„๊ตฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํด๋ผ๋ฆฌ์Šค. (๊ทธ์˜ ์ž‘๋…„ ๋ฐœํ‘œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ด๋ฏธ ๋ฒˆ์—ญ๋จ - ๋Œ€๋žต. ๋ฒˆ์—ญ)

Polaris๋Š” ํด๋Ÿฌ์Šคํ„ฐ์— ์„ค์น˜ํ•˜๊ฑฐ๋‚˜ ๋ช…๋ น์ค„ ๋ชจ๋“œ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง์ž‘ํ•˜์…จ๊ฒ ์ง€๋งŒ ์ด๋ฅผ ํ†ตํ•ด Kubernetes ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์ •์ ์œผ๋กœ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ช…๋ น์ค„ ๋ชจ๋“œ์—์„œ ์‹คํ–‰ํ•  ๋•Œ ๋ณด์•ˆ ๋ฐ ๋ชจ๋ฒ” ์‚ฌ๋ก€์™€ ๊ฐ™์€ ์˜์—ญ์„ ๋‹ค๋ฃจ๋Š” ๋‚ด์žฅ ํ…Œ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(kube-score์™€ ์œ ์‚ฌ). ๋˜ํ•œ config-lint, Copper ๋ฐ conftest์—์„œ์™€ ๊ฐ™์ด ๊ณ ์œ ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, Polaris๋Š” ๋‚ด์žฅ ํ…Œ์ŠคํŠธ์™€ ์‚ฌ์šฉ์ž ์ •์˜ ํ…Œ์ŠคํŠธ๋ผ๋Š” ๋‘ ๋„๊ตฌ ๋ฒ”์ฃผ์˜ ์ด์ ์„ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค.

Polaris๋ฅผ ๋ช…๋ น์ค„ ๋ชจ๋“œ๋กœ ์„ค์น˜ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ํ”„๋กœ์ ํŠธ ์›น์‚ฌ์ดํŠธ์˜ ์ง€์นจ.

์›๋ณธ ๊ธฐ์‚ฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์‹œ์ ์—๋Š” ๋ฒ„์ „ 1.0.3์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ค์น˜๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—์„œ Polaris๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. base-valid.yaml ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

$ polaris audit --audit-path base-valid.yaml

์ˆ˜ํ–‰๋œ ํ…Œ์ŠคํŠธ ๋ฐ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…๊ณผ ํ•จ๊ป˜ JSON ํ˜•์‹์˜ ๋ฌธ์ž์—ด์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์ถœ๋ ฅ์˜ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

{
  "PolarisOutputVersion": "1.0",
  "AuditTime": "0001-01-01T00:00:00Z",
  "SourceType": "Path",
  "SourceName": "test-data/base-valid.yaml",
  "DisplayName": "test-data/base-valid.yaml",
  "ClusterInfo": {
    "Version": "unknown",
    "Nodes": 0,
    "Pods": 2,
    "Namespaces": 0,
    "Controllers": 2
  },
  "Results": [
    /* ะดะปะธะฝะฝั‹ะน ัะฟะธัะพะบ */
  ]
}

์ „์ฒด ์ถœ๋ ฅ ๊ฐ€๋Šฅ ์—ฌ๊ธฐ์—.

kube-score์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Polaris๋Š” ๋งค๋‹ˆํŽ˜์ŠคํŠธ๊ฐ€ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์ถฉ์กฑํ•˜์ง€ ์•Š๋Š” ์˜์—ญ์˜ ๋ฌธ์ œ๋ฅผ ์‹๋ณ„ํ•ฉ๋‹ˆ๋‹ค.

  • ํฌ๋“œ์— ๋Œ€ํ•œ ์ƒํƒœ ํ™•์ธ์€ ์—†์Šต๋‹ˆ๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€์˜ ํƒœ๊ทธ๊ฐ€ ์ง€์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ๋Š” ๋ฃจํŠธ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ ๋ฐ CPU์— ๋Œ€ํ•œ ์š”์ฒญ ๋ฐ ์ œํ•œ์€ ์ง€์ •๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐ ํ…Œ์ŠคํŠธ๋Š” ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ์ค‘์š”๋„๊ฐ€ ์ง€์ •๋ฉ๋‹ˆ๋‹ค. ๊ฒฝ๊ณ  ๋˜๋Š” ์œ„ํ—˜. ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋‚ด์žฅ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๋ ค๋ฉด ๋‹ค์Œ์„ ์ฐธ์กฐํ•˜์„ธ์š”. ์„ ์  ์„œ๋ฅ˜ ๋น„์น˜.

์„ธ๋ถ€ ์‚ฌํ•ญ์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค --format score. ์ด ๊ฒฝ์šฐ Polaris๋Š” 1๋ถ€ํ„ฐ 100๊นŒ์ง€์˜ ์ˆซ์ž๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์ ์ˆ˜ (์˜ˆ: ํ‰๊ฐ€):

$ polaris audit --audit-path test-data/base-valid.yaml --format score
68

์ ์ˆ˜๊ฐ€ 100์— ๊ฐ€๊นŒ์šธ์ˆ˜๋ก ๋™์˜ ์ •๋„๊ฐ€ ๋†’์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ช…๋ น์˜ ์ข…๋ฃŒ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜๋ฉด polaris audit, 0๊ณผ ๊ฐ™๋‹ค๋Š” ๊ฒƒ์ด ๋ฐํ˜€์กŒ์Šต๋‹ˆ๋‹ค.

ํ™•์ธ polaris audit ๋‘ ๊ฐœ์˜ ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ XNUMX์ด ์•„๋‹Œ ์ฝ”๋“œ๋กœ ์ž‘์—…์„ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊นƒ๋ฐœ --set-exit-code-below-score 1-100 ๋ฒ”์œ„์˜ ์ž„๊ณ„๊ฐ’์„ ์ธ์ˆ˜๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์ ์ˆ˜๊ฐ€ ์ž„๊ณ„๊ฐ’ ๋ฏธ๋งŒ์ด๋ฉด ๋ช…๋ น์€ ์ข…๋ฃŒ ์ฝ”๋“œ 4๋กœ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํŠน์ • ์ž„๊ณ„๊ฐ’(์˜ˆ: 75)์ด ์žˆ๊ณ  ์ ์ˆ˜๊ฐ€ ๊ทธ ๋ฏธ๋งŒ์œผ๋กœ ๋–จ์–ด์ง€๋ฉด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ›์•„์•ผ ํ•  ๋•Œ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ๊นƒ๋ฐœ --set-exit-code-on-danger ์œ„ํ—˜ ํ…Œ์ŠคํŠธ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์‹คํŒจํ•˜๋ฉด ์ฝ”๋“œ 3์œผ๋กœ ๋ช…๋ น์ด ์‹คํŒจํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด์ œ ์ด๋ฏธ์ง€๋ฅผ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ €์žฅ์†Œ์—์„œ ๊ฐ€์ ธ์™”๋Š”์ง€ ํ™•์ธํ•˜๋Š” ์‚ฌ์šฉ์ž ์ง€์ • ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜ ํ…Œ์ŠคํŠธ๋Š” YAML ํ˜•์‹์œผ๋กœ ์ง€์ •๋˜๋ฉฐ ํ…Œ์ŠคํŠธ ์ž์ฒด๋Š” JSON ์Šคํ‚ค๋งˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ YAML ์ฝ”๋“œ ์กฐ๊ฐ์€ checkImageRepo:

checkImageRepo:
  successMessage: Image registry is valid
  failureMessage: Image registry is not valid
  category: Images
  target: Container
  schema:
    '$schema': http://json-schema.org/draft-07/schema
    type: object
    properties:
      image:
        type: string
        pattern: ^my-company.com/.+$

์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • successMessage โ€” ํ…Œ์ŠคํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜๋ฉด ์ด ์ค„์ด ์ธ์‡„๋ฉ๋‹ˆ๋‹ค.
  • failureMessage โ€” ์‹คํŒจํ•  ๊ฒฝ์šฐ ์ด ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  • category โ€” ๋‹ค์Œ ๋ฒ”์ฃผ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. Images, Health Checks, Security, Networking ะธ Resources;
  • target--- ๊ฐ์ฒด ์œ ํ˜•์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค(spec) ํ…Œ์ŠคํŠธ๊ฐ€ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•œ ๊ฐ’: Container, Pod ๋˜๋Š” Controller;
  • ํ…Œ์ŠคํŠธ ์ž์ฒด๋Š” ๊ฐœ์ฒด์— ์ง€์ •๋ฉ๋‹ˆ๋‹ค. schema JSON ์Šคํ‚ค๋งˆ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ํ…Œ์ŠคํŠธ์˜ ํ•ต์‹ฌ ๋‹จ์–ด๋Š” pattern ์ด๋ฏธ์ง€ ์†Œ์Šค๋ฅผ ํ•„์š”ํ•œ ์†Œ์Šค์™€ ๋น„๊ตํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ Polaris ๊ตฌ์„ฑ์„ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

checks:
  checkImageRepo: danger
customChecks:
  checkImageRepo:
    successMessage: Image registry is valid
    failureMessage: Image registry is not valid
    category: Images
    target: Container
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^my-company.com/.+$

(polaris-conf.yaml)

ํŒŒ์ผ์„ ๊ตฌ๋ฌธ ๋ถ„์„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ํ˜„์žฅ์—์„œ checks ํ…Œ์ŠคํŠธ์™€ ๊ทธ ์ค‘์š”๋„ ์ˆ˜์ค€์ด ๊ทœ์ •๋ฉ๋‹ˆ๋‹ค. ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ถœ์ฒ˜์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์™”์„ ๋•Œ ๊ฒฝ๊ณ ๋ฅผ ๋ฐ›๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•˜๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ๋Š” ์ˆ˜์ค€์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. danger.
  • ํ…Œ์ŠคํŠธ ์ž์ฒด checkImageRepo ๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ฐœ์ฒด์— ๋“ฑ๋ก customChecks.

ํŒŒ์ผ์„ ๋‹ค๋ฅธ ์ด๋ฆ„์œผ๋กœ ์ €์žฅ custom_check.yaml. ์ด์ œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค polaris audit ํ™•์ธ์ด ํ•„์š”ํ•œ YAML ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์„ ์–ธ๋ฌธ์„ ํ…Œ์ŠคํŠธํ•ด๋ณด์ž base-valid.yaml:

$ polaris audit --config custom_check.yaml --audit-path base-valid.yaml

ํŒ€ polaris audit ์œ„์— ์ง€์ •๋œ ์‚ฌ์šฉ์ž ํ…Œ์ŠคํŠธ๋งŒ ์‹คํ–‰ํ–ˆ๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด my-company.com/http-echo:1.0, Polaris๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ํฌํ•จ๋œ ๋งค๋‹ˆํŽ˜์Šคํ† ๊ฐ€ ์ด๋ฏธ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €์žฅ์†Œ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—์„œ ์ด์ „ ๋ช…๋ น์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. image-valid-mycompany.yaml.

์ด์ œ ์งˆ๋ฌธ์ด ์ƒ๊น๋‹ˆ๋‹ค. ๋‚ด์žฅ ํ…Œ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉ์ž ์ •์˜ ํ…Œ์ŠคํŠธ์™€ ํ•จ๊ป˜ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์šฉ์ดํ•˜๊ฒŒ! ๊ตฌ์„ฑ ํŒŒ์ผ์— ๋‚ด์žฅ๋œ ํ…Œ์ŠคํŠธ ์‹๋ณ„์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ๋ฅผ ์ทจํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

checks:
  cpuRequestsMissing: warning
  cpuLimitsMissing: warning
  # Other inbuilt checks..
  # ..
  # custom checks
  checkImageRepo: danger # !!!
customChecks:
  checkImageRepo:        # !!!
    successMessage: Image registry is valid
    failureMessage: Image registry is not valid
    category: Images
    target: Container
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^my-company.com/.+$

(config_with_custom_check.yaml)

์ „์ฒด ๊ตฌ์„ฑ ํŒŒ์ผ์˜ ์˜ˆ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—.

๋งค๋‹ˆํŽ˜์ŠคํŠธ ํ™•์ธ base-valid.yaml๋‚ด์žฅ ๋ฐ ์‚ฌ์šฉ์ž ์ •์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ polaris audit --config config_with_custom_check.yaml --audit-path base-valid.yaml

Polaris๋Š” ๋‚ด์žฅ๋œ ํ…Œ์ŠคํŠธ๋ฅผ ๋งž์ถคํ˜• ํ…Œ์ŠคํŠธ๋กœ ๋ณด์™„ํ•˜์—ฌ ๋‘ ์„ธ๊ณ„์˜ ์žฅ์ ์„ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด์— Rego๋‚˜ JavaScript์™€ ๊ฐ™์€ ๋” ๊ฐ•๋ ฅํ•œ ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ ์€ ๋” ์ •๊ตํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ๋ฐฉํ•ดํ•˜๋Š” ์ œํ•œ ์š”์†Œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Polaris์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ ์›น์‚ฌ์ดํŠธ.

๊ฐœ์š”

Kubernetes YAML ํŒŒ์ผ์„ ๊ฒ€์‚ฌํ•˜๊ณ  ํ‰๊ฐ€ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๊ฐ€ ๋งŽ์ง€๋งŒ, ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์„ค๊ณ„๋˜๊ณ  ์‹คํ–‰๋˜๋Š”์ง€ ๋ช…ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค..

์˜ˆ๋ฅผ ๋“ค์–ด, ํŒŒ์ดํ”„๋ผ์ธ์„ ํ†ต๊ณผํ•˜๋Š” Kubernetes ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์ทจํ•œ๋‹ค๋ฉด kubeval์€ ๊ทธ๋Ÿฌํ•œ ํŒŒ์ดํ”„๋ผ์ธ์˜ ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.. ๊ฐ์ฒด ์ •์˜๊ฐ€ Kubernetes API ์Šคํ‚ค๋งˆ๋ฅผ ์ค€์ˆ˜ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ฒ€ํ† ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ํ‘œ์ค€ ๋ชจ๋ฒ” ์‚ฌ๋ก€ ๋ฐ ํŠน์ • ์ •์ฑ… ์ค€์ˆ˜์™€ ๊ฐ™์€ ๋ณด๋‹ค ์ •๊ตํ•œ ํ…Œ์ŠคํŠธ๋กœ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ kube-score์™€ Polaris๊ฐ€ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

์š”๊ตฌ์‚ฌํ•ญ์ด ๋ณต์žกํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์„ธ๋ถ€์ ์œผ๋กœ ๋งž์ถคํ™”ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” Copper, config-lint ๋ฐ conftest๊ฐ€ ์ ํ•ฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค..

Conftest์™€ config-lint๋Š” YAML์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ •์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ •์˜ํ•˜๊ณ  Copper๋Š” ์ „์ฒด ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋ฅผ ์ œ๊ณตํ•˜๋ฏ€๋กœ ๋งค์šฐ ๋งค๋ ฅ์ ์ธ ์„ ํƒ์ž…๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด์— ์ด๋Ÿฌํ•œ ๋„๊ตฌ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด Polaris๋ฅผ ์„ ํ˜ธํ•˜๊ณ  ํ•„์š”ํ•œ ๊ฒƒ๋งŒ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ์ด ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•œ ๋Œ€๋‹ต์€ ์—†์Šต๋‹ˆ๋‹ค..

์•„๋ž˜ ํ‘œ์—๋Š” ๊ฐ ๋„๊ตฌ์— ๋Œ€ํ•œ ๊ฐ„๋žตํ•œ ์„ค๋ช…์ด ๋‚˜์™€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ˆ˜๋‹จ
๋ชฉ์ 
์ œํ•œ
์‚ฌ์šฉ์ž ํ…Œ์ŠคํŠธ

ํ๋ธŒ๋ฐœ
ํŠน์ • ๋ฒ„์ „์˜ API ์Šคํ‚ค๋งˆ์— ๋Œ€ํ•ด YAML ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
CRD๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค
์•„๋‹ˆ

ํ๋ธŒ ์ ์ˆ˜
๋ชจ๋ฒ” ์‚ฌ๋ก€์— ๋Œ€ํ•ด YAML ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.
๋ฆฌ์†Œ์Šค๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด Kubernetes API ๋ฒ„์ „์„ ์„ ํƒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
์•„๋‹ˆ

๊ตฌ๋ฆฌ
YAML ๋งค๋‹ˆํŽ˜์ŠคํŠธ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ JavaScript ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์ผ๋ฐ˜ ํ”„๋ ˆ์ž„์›Œํฌ
๋‚ด์žฅ๋œ ํ…Œ์ŠคํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ๋ฌธ์„œ
ะ”ะฐ

๊ตฌ์„ฑ ๋ฆฐํŠธ
YAML์— ํฌํ•จ๋œ ๋„๋ฉ”์ธ๋ณ„ ์–ธ์–ด๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์ผ๋ฐ˜ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ๊ตฌ์„ฑ ํ˜•์‹ ์ง€์›(์˜ˆ: Terraform)
์ค€๋น„๋œ ํ…Œ์ŠคํŠธ๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋‚ด์žฅ๋œ ์ฃผ์žฅ๊ณผ ํ•จ์ˆ˜๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
ะ”ะฐ

์ฝ˜ํ…Œ์ŠคํŠธ
Rego(ํŠน์ˆ˜ ์ฟผ๋ฆฌ ์–ธ์–ด)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž์‹ ๋งŒ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. OCI ๋ฒˆ๋“ค์„ ํ†ตํ•ด ์ •์ฑ… ๊ณต์œ  ๊ฐ€๋Šฅ
๋‚ด์žฅ๋œ ํ…Œ์ŠคํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ ˆ๊ณ ๋ฅผ ๋ฐฐ์›Œ์•ผ ํ•ด์š”. ์ •์ฑ… ๊ฒŒ์‹œ ์‹œ Docker Hub๋Š” ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
ะ”ะฐ

ํด๋ผ๋ฆฌ์Šค
ํ‘œ์ค€ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๊ธฐ์ค€์œผ๋กœ YAML ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๊ฒ€ํ† ํ•ฉ๋‹ˆ๋‹ค. JSON ์Šคํ‚ค๋งˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž์ฒด ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
JSON ์Šคํ‚ค๋งˆ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ ๊ธฐ๋Šฅ์ด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ
ะ”ะฐ

์ด๋Ÿฌํ•œ ๋„๊ตฌ๋Š” Kubernetes ํด๋Ÿฌ์Šคํ„ฐ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค์— ์˜์กดํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์„ค์น˜๊ฐ€ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์†Œ์Šค ํŒŒ์ผ์„ ํ•„ํ„ฐ๋งํ•˜๊ณ  ํ”„๋กœ์ ํŠธ์˜ ๋Œ์–ด์˜ค๊ธฐ ์š”์ฒญ ์ž‘์„ฑ์ž์—๊ฒŒ ๋น ๋ฅธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฒˆ์—ญ๊ฐ€์˜ ์ถ”์‹ 

๋ธ”๋กœ๊ทธ์—์„œ๋„ ์ฝ์–ด๋ณด์„ธ์š”.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€