참고 자료
- https://stackoverflow.com/questions/72645650/terminate-istio-proxy-after-cronjob-completion
- https://github.com/wafflestudio/waffle-world/blob/main/apps/snutt-dev/snutt-core/snutt-core.yaml
- https://www.howtogeek.com/devops/how-to-clean-up-old-kubernetes-jobs/
- https://kubernetes.io/docs/concepts/workloads/controllers/job/#clean-up-finished-jobs-automatically
1. 문제 정의
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: snutt-ev-batch-lecture-sync
labels:
app: snutt-ev-batch-lecture-sync
namespace: snutt-dev
spec:
concurrencyPolicy: Forbid
schedule: "0 19 * * *"
successfulJobsHistoryLimit: 2
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
metadata:
annotations:
sidecar.istio.io/inject: "true"
spec:
restartPolicy: OnFailure
serviceAccountName: snutt-ev-batch
containers:
- image: 405906814034.dkr.ecr.ap-northeast-2.amazonaws.com/snutt-dev/snutt-ev-batch:34
name: snutt-ev-batch-lecture-sync
env:
- name: JOB_NAMES
value: "SYNC_JOB"
- name: JAVA_OPTS
value: "-Duser.timezone=UTC"
- name: SPRING_PROFILES_ACTIVE
value: "dev"
- 수강 편람을 주기적으로 크롤링해오는 Batch Job은 현재 쿠버네티스의 CronJob API 오브젝트로서 동작하고 있습니다.
(가령, "45 */12 * * *" 값이 spec.schedule으로 등록된 CronJob은 매일 12시간 주기로 **시 45분에 동작합니다.)
- 이때 크롤링은 snutt-ev-batch-lecture-sync 컨테이너에서 잘 수행이 되지만 side-car 패턴으로 실행되는 istio를 inject해주면 (spec.template.metadata.annotations.sidecar.istio.io/inject: "true") side-car 컨테이너가 종료되지 않아 Job이 끝나고 Pod가 종료되지 않아 우리가 의도한 CronJob이 제대로 수행되지 않습니다.
2. 해결 방안
- 첫 번째로는 job/cronjob의 spec에 cmd와 args를 정의하여 아래처럼 envoy가 실행 중인 포트에 접근하여 side-car proxy container를 종료하는 것입니다.
command: ["/bin/bash", "-c"]
args:
- |
trap "curl --max-time 2 -s -f -XPOST http://127.0.0.1:15020/quitquitquit" EXIT
while ! curl -s -f http://127.0.0.1:15020/healthz/ready; do sleep 1; done
echo "Ready!"
< your job >
또는,
- command:
- /bin/sh
- -c
- |
until curl -fsI http://localhost:15021/healthz/ready; do echo \"Waiting for Sidecar...\"; sleep 3; done;
echo \"Sidecar available. Running the command...\";
<YOUR_COMMAND>;
x=$(echo $?); curl -fsI -X POST http://localhost:15020/quitquitquit && exit $x
- 두 번째로는 아예 CronJob에 Envoy를 주입하지 않아 서비스메쉬의 범위에서 제외하는 것입니다.
apiVersion: batch/v1beta1
kind: CronJob
metadata:
...
spec:
...
jobTemplate:
spec:
template:
metadata:
annotations:
# disable istio on the pod due to this issue:
# https://github.com/istio/istio/issues/11659
sidecar.istio.io/inject: "false"
위 방식을 사용한다면, 이 포스트 처음에 보여드린 manifest는 다음과 같이 바뀔 수 있겠습니다.
( sidecar.istio.io/inject: "true" -> sidecar.istio.io/inject: "false" )
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: snutt-ev-batch-lecture-sync
labels:
app: snutt-ev-batch-lecture-sync
namespace: snutt-dev
spec:
concurrencyPolicy: Forbid
schedule: "0 19 * * *"
successfulJobsHistoryLimit: 2
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
spec:
restartPolicy: OnFailure
serviceAccountName: snutt-ev-batch
containers:
- image: 405906814034.dkr.ecr.ap-northeast-2.amazonaws.com/snutt-dev/snutt-ev-batch:34
name: snutt-ev-batch-lecture-sync
env:
- name: JOB_NAMES
value: "SYNC_JOB"
- name: JAVA_OPTS
value: "-Duser.timezone=UTC"
- name: SPRING_PROFILES_ACTIVE
value: "dev"
- 별개로, Kubernetes v1.23부터 stable하게 지원하는 TTL 메커니즘을 사용하여 Job 또는 CronJob의 status와 관계 없이 일정 시간이 흐르면 Pod를 삭제할 수 있습니다. 다만, manifest를 정의하는 시점에 미리 job의 실행 시간을 예측해서 ttlSecondsAfterFinished 값을 설정해야 하므로 Batch가 제대로 돌지 않았음에도 Pod가 종료되는 불상사가 발생할 가능성도 배제해서는 안 됩니다.
apiVersion: batch/v1
kind: CronJob
metadata:
name: demo-cron
spec:
schedule: "* * * * *"
jobTemplate:
spec:
ttlSecondsAfterFinished: 300
template:
spec:
containers:
- name: demo-cron
image: busybox:latest
command: ["/bin/sh", "-c", "Job complete!"]
댓글