Kubernetes executor 문제 해결

Kubernetes executor를 사용할 때 다음과 같은 오류가 일반적으로 발생합니다.

Job failed (system failure): timed out waiting for pod to start

클러스터가 빌드 pod를 poll_timeout으로 정의된 시간 내에 스케줄링하지 못하면 빌드 pod는 오류를 반환합니다. Kubernetes Scheduler에서 해당 pod를 삭제할 수 있어야 합니다.

이 문제를 해결하려면 config.toml 파일에서 poll_timeout 값을 늘리세요.

context deadline exceeded

작업 로그에서의 context deadline exceeded 오류는 보통 특정 클러스터 API 요청에 대해 Kubernetes API 클라이언트가 시간 초과에 도달했음을 나타냅니다.

pods, secrets, ConfigMaps 및 다른 코어 (v1) 리소스에 대한 생성 또는 삭제 작업의 오류율의 증가 또는 공통 응답 대기 시간의 증가를 확인하세요.

kube-apiserver 작업에서의 시간 초과 오류 로그는 다음과 같이 나타날 수 있습니다:

Job failed (system failure): prepare environment: context deadline exceeded
Job failed (system failure): prepare environment: setting up build pod: context deadline exceeded

kube-apiserver 서비스 실패는 빌드 pod를 생성하는 동안 또는 완료 후 정리를 시도하는 동안 발생할 수 있습니다:

Error cleaning up secrets: etcdserver: request timed out
Error cleaning up secrets: etcdserver: leader changed

Error cleaning up pod: etcdserver: request timed out, possibly due to previous leader failure
Error cleaning up pod: etcdserver: request timed out
Error cleaning up pod: context deadline exceeded

Dial tcp xxx.xx.x.x:xxx: i/o timeout

이 오류는 Kubernetes API 서버가 러너 관리자에 의해 접근할 수 없음을 일반적으로 나타냅니다. 이 문제를 해결하려면 다음을 수행하세요:

  • 네트워크 보안 정책을 사용하는 경우 일반적으로 443포트 또는 6443포트 또는 둘 다에서 Kubernetes API에 액세스 권한을 부여하세요.
  • Kubernetes API가 실행 중인지 확인하세요.

Kubernetes API 통신 시 연결이 거부됨

GitLab Runner가 Kubernetes API로 요청을 보내고 실패하는 경우, 일반적으로 kube-apiserver 이 과부하되어 API 요청을 수락하거나 처리할 수 없기 때문일 수 있습니다.

Error cleaning up podJob failed (system failure): prepare environment: waiting for pod running

다음 오류는 Kubernetes가 작업 pod를 시간 내에 스케줄할 수 없는 경우 발생합니다. GitLab Runner는 pod가 준비 상태가 될 때까지 기다리지만 실패한 후 pod를 정리하려고 하고, 이로 인해 실패할 수 있습니다.

Error: Error cleaning up pod: Delete "https://xx.xx.xx.x:443/api/v1/namespaces/gitlab-runner/runner-0001": dial tcp xx.xx.xx.x:443 connect: connection refused

Error: Job failed (system failure): prepare environment: waiting for pod running: Get "https://xx.xx.xx.x:443/api/v1/namespaces/gitlab-runner/runner-0001": dial tcp xx.xx.xx.x:443 connect: connection refused

문제 해결을 위해 Kubernetes 주 노드 및 kube-apiserver 인스턴스를 실행하는 모든 노드를 확인하세요. 클러스터에서 스케일 업할 목표 pod 수를 관리하는 데 필요한 모든 리소스가 있는지 확인하세요.

Ready 상태에 도달하기까지 GitLab Runner가 pod를 기다리는 시간을 변경하려면 poll_timeout 설정을 사용하세요.

Pod가 예정된 대로 스케줄되지 않거나 왜 스케줄되지 않았는지에 대해 더 잘 이해하려면 Kubernetes Scheduler에 대해 읽어보세요.

request did not complete within requested timeout

빌드 pod 생성 중에 관찰된 request did not complete within requested timeout 메시지는 구성된 admission control webhook이 Kubernetes 클러스터에서 시간 초과되고 있음을 나타냅니다.

Admission control webhooks는 해당하는 모든 API 요청에 대해 클러스터 수준의 관리적 제어 요소로 서로 제어할 수 있으며 시간 초과될 경우 오류를 일으킬 수 있습니다.

만일 GitLab Runner로부터의 Kubernetes API 호출이 admission control webhook을 통과할 필요가 없다면 podAnnotations 또는 podLabels를 구성하여 GitLab Runner pod에서 제외 레이블/주석을 적용할 수 있습니다.

예를 들어, GitLab Runner 관리자 pod가 만든 API 요청을 DataDog Admission Controller webhook이 차단하지 않도록 하려면 다음과 같이 추가할 수 있습니다:

podLabels:
  admission.datadoghq.com/enabled: false

Kubernetes 클러스터의 admission control webhooks을 나열하려면 다음과 같이 실행하세요:

kubectl get validatingwebhookconfiguration -o yaml
kubectl get mutatingwebhookconfiguration -o yaml

admission control webhook의 시간 초과로 인한 오류는 다음과 같이 나타날 수 있습니다:

Job failed (system failure): prepare environment: Timeout: request did not complete within requested timeout
Job failed (system failure): prepare environment: setting up credentials: Timeout: request did not complete within requested timeout

admission control webhook의 실패는 다음과 같이 나타날 수 있습니다:

Job failed (system failure): prepare environment: setting up credentials: Internal error occurred: failed calling webhook "example.webhook.service"

fatal: unable to access 'https://gitlab-ci-token:token@example.com/repo/proj.git/': 호스트 example.com을(를) 찾을 수 없음

만약 도우미 이미지alpine 플레이버를 사용하는 경우, Alpine의 musl DNS 리졸버와 관련된 DNS 이슈가 발생할 수 있습니다.

이 문제를 해결하려면 helper_image_flavor = "ubuntu" 옵션을 사용하면 됩니다.

docker: Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running?

이 오류는 Docker-in-Docker를 사용할 때, DIND 서비스가 완전히 시작되기 전에 DIND 서비스에 액세스를 시도할 경우 발생할 수 있습니다. 자세한 내용은 이 이슈를 참조하세요.

curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443

이 오류는 Docker-in-Docker를 사용할 때, DIND의 최대 전송 단위(MTU)가 Kubernetes 오버레이 네트워크보다 큰 경우에 발생할 수 있습니다. DIND는 기본 MTU를 1500으로 사용하며, 이는 기본 오버레이 네트워크를 통과하는 데 너무 큽니다. DIND MTU는 서비스 정의에서 변경할 수 있습니다:

services:
  - name: docker:dind
    command: ["--mtu=1450"]

MountVolume.SetUp failed for volume "kube-api-access-xxxxx" : chown is not supported by windows

CI/CD 작업을 실행하는 중에 다음과 같은 오류를 받을 수 있습니다.

MountVolume.SetUp failed for volume "kube-api-access-xxxxx" : chown c:\var\lib\kubelet\pods\xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\volumes\kubernetes.io~projected\kube-api-access-xxxxx\..2022_07_07_20_52_19.102630072\token: not supported by windows

이 문제는 노드 선택자를 사용하여 서로 다른 운영 체제와 아키텍처를 갖는 노드에서 빌드를 실행할 때 발생합니다.

이 문제를 해결하려면, nodeSelector를 설정하여 runner 관리자 pod가 항상 Linux 노드에서 예약되도록 해야 합니다. 예를 들어, values.yaml 파일에 다음을 포함해야 합니다:

nodeSelector:
  kubernetes.io/os: linux

Build pods are assigned the worker node’s IAM role instead of Runner IAM role

이 문제는 worker 노드 IAM 역할이 올바른 역할을 가정할 수 있도록 권한을 추가하지 않았을 때 발생합니다. 이 문제를 해결하려면 worker 노드 IAM 역할의 신뢰 관계에 sts:AssumeRole 권한을 추가하면 됩니다:

{
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::<AWS_ACCOUNT_NUMBER>:role/<IAM_ROLE_NAME>"
    },
    "Action": "sts:AssumeRole"
}

Preparation failed: invalid pull policy for image 'image-name:latest': pull_policy ([Always]) defined in GitLab pipeline config is not one of the allowed_pull_policies ([])

이 문제는 .gitlab-ci.yml에서 pull_policy를 지정했지만 Runner의 구성 파일에 정책이 구성되지 않았을 때 발생합니다. 이 문제를 해결하려면 Docker pull 정책을 제한에 따라 구성에 allowed_pull_policies를 추가하면 됩니다.

백그라운드 프로세스로 인해 작업이 멈추고 시간 초과 발생

작업 실행 중에 시작된 백그라운드 프로세스가 빌드 작업이 종료되지 않도록하는 경우가 있습니다. 이를 방지하려면 다음과 같이 할 수 있습니다:

  • 프로세스를 두 번 포크합니다. 예를 들어, command_to_run < /dev/null &> /dev/null &.
  • 작업 스크립트를 종료하기 전에 프로세스를 종료합니다.

캐시 관련 permission denied 에러

작업에서 생성된 파일과 폴더에는 특정한 UNIX 소유 및 권한이 있습니다. 파일 및 폴더가 아카이브화되거나 추출될 때 UNIX 세부 정보가 유지됩니다. 그러나 파일 및 폴더는 도우미 이미지USER 구성과 일치하지 않을 수 있습니다.

Creating cache ... 단계에서 권한 관련 오류가 발생하는 경우 다음과 같이 할 수 있습니다:

  • 해결책으로는, 캐시된 파일을 생성하는 작업 스크립트에서 데이터가 수정되었는지 조사하세요.
  • 일시적인 해결책으로는, 일치하는 (before_/after_)script: 지시어에 일치하는 chownchmod 명령을 추가하세요.

초기화 시스템이 있는 빌드 컨테이너에서 불필요한 쉘 프로세스

프로세스 트리에 쉘 프로세스가 포함될 수 있습니다. 이는 다음 중 하나일 때 발생할 수 있습니다:

  • FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGYfalse이고 FF_USE_DUMB_INIT_WITH_KUBERNETES_EXECUTORtrue일 때.
  • 빌드 이미지의 ENTRYPOINT가 초기화 시스템(예: tini-init 또는 dumb-init)인 경우.
UID    PID   PPID  C STIME TTY          TIME CMD
root     1      0  0 21:58 ?        00:00:00 /scripts-37474587-5556589047/dumb-init -- sh -c if [ -x /usr/local/bin/bash ]; then .exec /usr/local/bin/bash  elif [ -x /usr/bin/bash ]; then .exec /usr/bin/bash  elif [ -x /bin/bash ]; then .exec /bin/bash  elif [ -x /usr/local/bin/sh ]; then .exec /usr/local/bin/sh  elif [ -x /usr/bin/sh ]; then .exec /usr/bin/sh  elif [ -x /bin/sh ]; then .exec /bin/sh  elif [ -x /busybox/sh ]; then .exec /busybox/sh  else .echo shell not found .exit 1 fi
root     7      1  0 21:58 ?        00:00:00 /usr/bin/bash <---------------- 이게 뭔가요???
root    26      1  0 21:58 ?        00:00:00 sh -c (/scripts-37474587-5556589047/detect_shell_script /scripts-37474587-5556589047/step_script 2>&1 | tee -a /logs-37474587-5556589047/output.log) &
root    27     26  0 21:58 ?        00:00:00  \_ /usr/bin/bash /scripts-37474587-5556589047/step_script
root    32     27  0 21:58 ?        00:00:00  |   \_ /usr/bin/bash /scripts-37474587-5556589047/step_script
root    37     32  0 21:58 ?        00:00:00  |       \_ ps -ef --forest
root    28     26  0 21:58 ?        00:00:00  \_ tee -a /logs-37474587-5556589047/output.log

이 초기화 시스템에 의해 실행되는 쉘 검출 스크립트에 의해 실행된 쉘 프로세스(PID 1)가 이 쉘 프로세스이며, 불필요한 것이 아니며 빌드 컨테이너가 초기화 시스템을 사용하는 경우 일반적인 동작입니다.

러너 파드는 작업을 실행하지 못하고 타임아웃되는 문제가 있음

러너 파드가 GitLab에 등록된 후 작업을 실행하려고 시도하지만 실패하고 최종적으로 작업이 타임아웃됩니다. 다음과 같은 오류가 보고됩니다.

시간 초과 실패가 발생했거나 작업이 멈춘 상태입니다. 타임아웃 제한을 확인하거나 다시 시도하세요.

이 작업에는 trace가 없습니다.

이 경우, 러너는 다음과 같은 오류를 받을 수 있습니다.

`jobs/request` API에 연결할 때 HTTP 204 No content 응답 코드가 반환되었습니다.

이 문제를 해결하려면 API에 수동으로 POST 요청을 보내어 TCP 연결이 멈춰 있는지 확인합니다. TCP 연결이 멈춰 있다면, 러너는 CI 작업 payload를 요청할 수 없을 수 있습니다.

gcs-fuse-csi-driver를 사용할 때 init-permissions 컨테이너의 이름을 예약하지 못하는 문제

gcs-fuse-csi-driver csi 드라이버는 초기 컨테이너에 볼륨을 마운트하는 것을 지원하지 않습니다. 이 드라이버를 사용할 때 초기 컨테이너가 시작하는 데 실패할 수 있습니다. 이 버그를 해결하려면 드라이버 프로젝트에서 Kubernetes 1.28에서 도입된 기능을 지원해야 합니다.

오류: 읽기 전용 루트 파일 시스템 컨테이너만 허용됨

읽기 전용으로 마운트된 루트 파일 시스템에서 실행되어야 하는 어드미션 정책을 강제하는 클러스터에서는 다음과 같은 오류가 발생할 수 있습니다.

  • GitLab 러너를 설치합니다.
  • GitLab 러너가 빌드 파드를 예약하려고 시도합니다.

이러한 어드미션 정책은 보통 GatekeeperKyverno 같은 어드미션 컨트롤러에 의해 강제됩니다. 예를 들어, 컨테이너가 읽기 전용 루트 파일 시스템에서 실행되어야 하는 정책은 readOnlyRootFilesystem Gatekeeper 정책입니다.

이 문제를 해결하려면:

  • 클러스터에 배포되는 모든 파드는 컨테이너에 대해 securityContext.readOnlyRootFilesystemtrue로 설정하여 어드미션 정책을 준수해야 합니다. 이렇게 하면 어드미션 컨트롤러가 파드를 차단하지 않습니다.
  • 루트 파일 시스템이 읽기 전용으로 마운트되어 있더라도 컨테이너는 성공적으로 실행되고 파일 시스템에 쓸 수 있어야 합니다.

GitLab 러너의 경우

GitLab 러너가 GitLab 러너 Helm 차트로 배포된 경우, GitLab 차트 구성을 업데이트해야 합니다:

  • 적절한 securityContext 값:

    <...>
    securityContext:
      readOnlyRootFilesystem: true
    <...>
    
  • 파드가 쓸 수 있는 쓰기 가능한 파일 시스템이 마운트되어 있어야 합니다:

    <...>
    volumeMounts:
    - name: tmp-dir
      mountPath: /tmp
    volumes:
    - name: tmp-dir
      emptyDir:
        medium: "Memory"
    <...>
    

빌드 파드의 경우

빌드 파드를 읽기 전용 루트 파일 시스템에서 실행하려면 config.toml에서 다른 컨테이너의 보안 컨텍스트를 구성해야 합니다. 빌드 파드에 대한 GitLab 차트 변수 runners.config를 설정할 수 있습니다:

runners:
  config: |
   <...>
   [[runners]]
     [runners.kubernetes.build_container_security_context]
       read_only_root_filesystem = true
     [runners.kubernetes.init_permissions_container_security_context]
       read_only_root_filesystem = true
     [runners.kubernetes.helper_container_security_context,omitempty]
       read_only_root_filesystem = true
     # 서비스가 사용된 작업의 경우에만 이 섹션이 필요합니다
     [runners.kubernetes.service_container_security_context,omitempty]
       read_only_root_filesystem = true
   <...>

빌드 파드와 해당 컨테이너가 읽기 전용 파일 시스템에서 성공적으로 실행되도록 하려면, 빌드 파드가 쓸 수 있는 파일 시스템을 루트 디렉토리와 홈 디렉토리에 설정해야 합니다. 필요하면 다른 위치에 대한 빌드 프로세스의 쓰기 액세스를 보장하십시오.

일반적으로 홈 디렉토리는 프로그램이 성공적으로 실행되기 위해 필요한 설정 및 기타 데이터를 저장해야 하므로 쓸 수 있어야 합니다. 예를 들어 git 이진 파일은 홈 디렉토리에 쓸 수 있기를 기대하는 프로그램 중 하나입니다.

서로 다른 컨테이너 이미지에서 경로에 관계없이 홈 디렉토리를 쓰기 가능하게 만드려면:

  1. 안정적인 경로에 볼륨을 마운트합니다 (어떤 빌드 이미지를 사용하더라도).
  2. 모든 빌드에 대해 환경 변수 $HOME을 설정하여 홈 디렉토리를 변경합니다.

빌드 파드 및 해당 컨테이너는 config.toml에서 GitLab 차트 변수 runners.config의 값을 업데이트하여 구성할 수 있습니다.

runners:
  config: |
   <...>
   [[runners]]
     environment = ["HOME=/build_home"]
     [[runners.kubernetes.volumes.empty_dir]]
       name = "repo"
       mount_path = "/builds"
     [[runners.kubernetes.volumes.empty_dir]]
       name = "build-home"
       mount_path = "/build_home"
   <...>

참고: emptyDir 대신에 다른 지원되는 볼륨 유형을 사용할 수 있습니다. 명시적으로 처리되지 않고 빌드 아티팩트로 저장되지 않는 모든 파일은 보통 일시적이므로, 대부분의 경우 emptyDir가 작동합니다.

AWS EKS: Pod 정리 중 오류 발생: pods “runner-**“을(를) 찾을 수 없거나 상태가 “실패함”

Amazon EKS 영역 재분배 기능은 오토스케일링 그룹의 가용 영역을 균형잡게 맞춥니다. 이 기능은 한 가용 영역의 노드를 중지하고 다른 가용 영역에 노드를 생성할 수 있습니다.

러너 작업은 중지되고 다른 노드로 이동할 수 없습니다. 이 오류를 해결하려면 러너 작업을 위해 이 기능을 비활성화하세요.