Skip to content

Helm

Kubernetes 패키지 관리 (npm이나 pip같은)

Categories

Commands

  • completion - 지정된 셸에 대한 자동완성 스크립트 생성
  • create - 주어진 이름으로 새 차트 생성
  • dependency - 차트의 의존성 관리
  • env - Helm 클라이언트 환경 정보
  • get - 명명된 릴리스의 확장 정보 다운로드
  • help - 모든 명령어에 대한 도움말
  • history - 릴리스 히스토리 조회
  • install - 차트 설치
  • lint - 차트의 잠재적 문제 검사
  • list - 릴리스 목록 조회
  • package - 차트 디렉토리를 차트 아카이브로 패키징
  • plugin - Helm 플러그인 설치, 목록 조회 또는 제거
  • pull - 저장소에서 차트 다운로드 및 (선택적으로) 로컬 디렉토리에 압축 해제
  • push - 차트를 원격으로 푸시
  • registry - 레지스트리에 로그인 또는 로그아웃
  • repo - 차트 저장소 추가, 목록 조회, 제거, 업데이트 및 인덱싱
  • rollback - 릴리스를 이전 리비전으로 롤백
  • search - 차트에서 키워드 검색
  • show - 차트 정보 표시
  • status - 명명된 릴리스의 상태 표시
  • template - 로컬에서 템플릿 렌더링
  • test - 릴리스에 대한 테스트 실행
  • uninstall - 릴리스 제거
  • upgrade - 릴리스 업그레이드
  • verify - 주어진 경로의 차트가 서명되고 유효한지 검증
  • version - Helm 버전 정보 출력

헬름의 목적

헬름은 "차트" 라고 하는 쿠버네티스 패키지를 관리하는 도구이다. 헬름으로 다음과 같은 것들을 할 수 있다.

  • 스크래치(scratch)부터 새로운 차트 생성
  • 차트 아카이브(tgz) 파일로 차트 패키징
  • 차트가 저장되는 곳인 차트 리포지터리와 상호작용
  • 쿠버네티스 클러스터에 차트 인스톨 및 언인스톨
  • 헬름으로 설치된 차트들의 릴리스 주기 관리

Install

snap이 있다면 이걸로 설치.

sudo snap install helm --classic

개념

헬름에는 다음과 같은 중요한 3가지 개념이 있다.

차트
쿠버네티스 애플리케이션의 인스턴스를 생성하는 데에 필요한 정보의 꾸러미이다.
설정
릴리스 가능한 객체를 생성하기 위해 패키징된 차트로 병합될 수 있는 설정 정보를 가진다.
릴리스
"차트"의 구동중 인스턴스이며, 특정 "설정"이 결합되어 있다.

배포 방법

Nginx 설치하기

# Stable Chart
helm repo add stable https://charts.helm.sh/stable

# Bitnami NginX는 통합된 php, mysql, nginx 개발환경을 제공한다.
helm repo add bitnami https://charts.bitnami.com/bitnami

# Helm Chart를 업데이트 해준다.
helm repo update

# 이번 실습에선 nginx 서버를 설치해야 하므로 nginx와 관련된 repository를 검색한다.
helm search repo nginx

# bitnami/nginx repository를 통해 서버를 설치한다.
helm install nginx bitnami/nginx

다음과 같이 출력됨:

NAME: nginx
LAST DEPLOYED: Thu Dec 18 16:00:38 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None
NOTES:
CHART NAME: nginx
CHART VERSION: 22.3.9
APP VERSION: 1.29.4

⚠ WARNING: Since August 28th, 2025, only a limited subset of images/charts are available for free.
    Subscribe to Bitnami Secure Images to receive continued support and security updates.
    More info at https://bitnami.com and https://github.com/bitnami/containers/issues/83267

** Please be patient while the chart is being deployed **
NGINX can be accessed through the following DNS name from within your cluster:

    nginx.default.svc.cluster.local (port 80)

To access NGINX from outside the cluster, follow the steps below:

1. Get the NGINX URL by running these commands:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace default -w nginx'

    export SERVICE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].port}" services nginx)
    export SERVICE_IP=$(kubectl get svc --namespace default nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo "http://${SERVICE_IP}:${SERVICE_PORT}"
WARNING: Rolling tag detected (bitnami/nginx:latest), please note that it is strongly recommended to avoid using rolling tags in a production environment.
+info https://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-understand-rolling-tags-containers-index.html
WARNING: Rolling tag detected (bitnami/git:latest), please note that it is strongly recommended to avoid using rolling tags in a production environment.
+info https://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-understand-rolling-tags-containers-index.html
WARNING: Rolling tag detected (bitnami/nginx-exporter:latest), please note that it is strongly recommended to avoid using rolling tags in a production environment.
+info https://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-understand-rolling-tags-containers-index.html

WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs:
  - cloneStaticSiteFromGit.gitSync.resources
  - resources
+info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/

요약하면 둘 중 하나의 방법으로 IP 주소 확인해서 들어가라:

# 방법 1
kubectl get svc --namespace default -w nginx

# 방법 2
export SERVICE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].port}" services nginx)
export SERVICE_IP=$(kubectl get svc --namespace default nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "http://${SERVICE_IP}:${SERVICE_PORT}"

접속 안되는 현상 해결 방법

그런데 k3s 같은걸 설치했거나 별도의 로드벨런서를 설치했다면 아마 다음과 같이 출력될거다:

kubectl get svc --namespace default -w nginx

출력:

NAME    TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
nginx   LoadBalancer   10.43.132.171   <pending>     80:30554/TCP,443:32117/TCP   35s

EXTERNAL-IP 가 계속 <pending> 상태에서 머물러 있다. 문제를 확인하기 위해 관련 pod 를 찾아보자:

kubectl get pods -n kube-system

다음과 같이 출력된다:

NAME                                      READY   STATUS      RESTARTS   AGE
coredns-6d668d687-sk8z4                   1/1     Running     0          28m
helm-install-traefik-btnrc                0/1     Completed   1          28m
helm-install-traefik-crd-thplf            0/1     Completed   0          28m
local-path-provisioner-869c44bfbd-khd2x   1/1     Running     0          28m
metrics-server-7bfffcd44-bp7lr            1/1     Running     0          28m
svclb-nginx-526a66f9-pbzkk                0/2     Pending     0          8m20s
svclb-traefik-33133399-bhx7l              2/2     Running     0          27m
traefik-865bd56545-995lq                  1/1     Running     0          27m

nginx 관련 pod 가 READY 0/2, Pending 상태 인걸 확인할 수 있다.

해당 pod (svclb-nginx-526a66f9-pbzkk) 를 확인하자:

kubectl describe pod svclb-nginx-526a66f9-pbzkk -n kube-system

다음과 같이 출력된다:

Name:                 svclb-nginx-526a66f9-pbzkk
Namespace:            kube-system
Priority:             2000001000
Priority Class Name:  system-node-critical
Service Account:      svclb
Node:                 <none>
Labels:               app=svclb-nginx-526a66f9
                      controller-revision-hash=7b448cb6fb
                      pod-template-generation=1
                      svccontroller.k3s.cattle.io/svcname=nginx
                      svccontroller.k3s.cattle.io/svcnamespace=default
Annotations:          <none>
Status:               Pending
IP:
IPs:                  <none>
Controlled By:        DaemonSet/svclb-nginx-526a66f9
Containers:
  lb-tcp-80:
    Image:      rancher/klipper-lb:v0.4.13
    Port:       80/TCP (lb-tcp-80)
    Host Port:  80/TCP (lb-tcp-80)
    Environment:
      SRC_PORT:    80
      SRC_RANGES:  0.0.0.0/0
      DEST_PROTO:  TCP
      DEST_PORT:   80
      DEST_IPS:    10.43.132.171
    Mounts:        <none>
  lb-tcp-443:
    Image:      rancher/klipper-lb:v0.4.13
    Port:       443/TCP (lb-tcp-443)
    Host Port:  443/TCP (lb-tcp-443)
    Environment:
      SRC_PORT:    443
      SRC_RANGES:  0.0.0.0/0
      DEST_PROTO:  TCP
      DEST_PORT:   443
      DEST_IPS:    10.43.132.171
    Mounts:        <none>
Conditions:
  Type           Status
  PodScheduled   False
Volumes:         <none>
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     CriticalAddonsOnly op=Exists
                 node-role.kubernetes.io/control-plane:NoSchedule op=Exists
                 node-role.kubernetes.io/master:NoSchedule op=Exists
                 node.kubernetes.io/disk-pressure:NoSchedule op=Exists
                 node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                 node.kubernetes.io/not-ready:NoExecute op=Exists
                 node.kubernetes.io/pid-pressure:NoSchedule op=Exists
                 node.kubernetes.io/unreachable:NoExecute op=Exists
                 node.kubernetes.io/unschedulable:NoSchedule op=Exists
Events:
  Type     Reason            Age    From               Message
  ----     ------            ----   ----               -------
  Warning  FailedScheduling  9m10s  default-scheduler  0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports. preemption: 0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports.
  Warning  FailedScheduling  3m47s  default-scheduler  0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports. preemption: 0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports.

하단에 경고 이벤트가 출력되어 있다:

0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports. preemption: 0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports.

번역하면:

사용 가능한 노드는 0/1개입니다. 요청된 Pod 포트에 사용할 수 있는 여유 포트가 1개 노드에 없습니다. 선점: 사용 가능한 노드는 0/1개입니다. 요청된 Pod 포트에 사용할 수 있는 여유 포트가 1개 노드에 없습니다.

K3s는 기본적으로 Traefik Ingress Controller가 80/443 포트를 선점하고 있습니다.

포트 사용 확인 방법:

# 80, 443 포트를 사용하는 프로세스 확인
sudo netstat -tulpn | grep ':80\|:443'

# 또는
sudo ss -tulpn | grep ':80\|:443'

# Traefik 서비스 확인
kubectl get svc -n kube-system traefik

LoadBalancer 대신 Traefik Ingress 로 접근하는 것이 K3s의 표준 방식입니다:

# Helm으로 Ingress 포함하여 재설치
helm upgrade nginx bitnami/nginx \
  --set service.type=ClusterIP \
  --set ingress.enabled=true \
  --set ingress.hostname=nginx.local

이 경우 hostname 으로 지정한 nginx.local 으로 접속해야 한다. /etc/hosts 파일을 갱신하던가 해라.

참고로 다른 포트 사용하는 방법도 있다: (비추)

helm upgrade nginx bitnami/nginx \
  --set service.ports.http=8080 \
  --set service.ports.https=8443

Troubleshooting

WARNING: Kubernetes configuration file is ***-readable. This is insecure. Location: ~/.kube/config

관련 명령을 치면 이런 경고가 출력된다.

WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: ~/.kube/config
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: ~/.kube/config

chmod 600 ~/.kube/config 명령으로 접근 권한 바꾸자.

See also

Favorite site