Helm
lastmod 2025-12-21created 2022-10-0118 edits
Kubernetes package management (like npm or pip)
Categories
Commands
-
completion- Generate autocompletion scripts for the specified shell -
create- Create a new chart with the given name -
dependency- Manage a chart's dependencies -
env- Helm client environment information -
get- Download extended information of a named release -
help- Help about any command -
history- Fetch release history -
install- Install a chart -
lint- Examine a chart for possible issues -
list- List releases -
package- Package a chart directory into a chart archive -
plugin- Install, list, or uninstall Helm plugins -
pull- Download a chart from a repository and (optionally) extract it in a local directory -
push- Push a chart to a remote -
registry- Log in to or log out from a registry -
repo- Add, list, remove, update, and index chart repositories -
rollback- Roll back a release to a previous revision -
search- Search for a keyword in charts -
show- Show information about a chart -
status- Display the status of the named release -
template- Locally render templates -
test- Run tests for a release -
uninstall- Uninstall a release -
upgrade- Upgrade a release -
verify- Verify that a chart at the given path has been signed and is valid -
version- Print Helm version information
Purpose of Helm
Helm is a tool for managing Kubernetes packages called "charts". With Helm you can do the following.
- Create new charts from scratch
- Package charts into chart archive (tgz) files
- Interact with chart repositories, where charts are stored
- Install and uninstall charts in a Kubernetes cluster
- Manage the release cycle of charts installed with Helm
Install
If you have snap, install it with that.
Concepts
Helm has three important concepts.
- Chart
- A bundle of information needed to create an instance of a Kubernetes application.
- Config
- Contains configuration information that can be merged into a packaged chart to create a releasable object.
- Release
- A running instance of a "chart", combined with a specific "config".
Deployment
- (Kubernetes) From building a docker image to helm deployment (Part 1) :: Jay's Code Factory
- (Kubernetes) From building a docker image to helm deployment (Part 2) :: Jay's Code Factory
- Kubernetes Helm - Creating and deploying a Chart (version management and Release management)
Installing Nginx
- Installing nginx with a Helm Chart
- (kubernetes) Installing the nginx ingress controller with Helm — Gaebalnyangbal
# 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
The output looks like this:
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/
In short, find the IP address with one of these two methods and connect:
# 방법 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}"
Fixing the connection problem
However, if you have installed something like k3s or a separate load balancer, you will probably get output like this:
Output:
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 stays in the <pending> state. To find the problem, look up the related pod:
The output looks like this:
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
You can see that the nginx-related pod is READY 0/2 and in the Pending state.
Inspect that pod (svclb-nginx-526a66f9-pbzkk):
The output looks like this:
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.
A warning event is printed at the bottom:
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.
Translated into Korean:
사용 가능한 노드는 0/1개입니다. 요청된 Pod 포트에 사용할 수 있는 여유 포트가 1개 노드에 없습니다. 선점: 사용 가능한 노드는 0/1개입니다. 요청된 Pod 포트에 사용할 수 있는 여유 포트가 1개 노드에 없습니다.
In K3s, the Traefik Ingress Controller occupies ports 80/443 by default.
How to check port usage:
# 80, 443 포트를 사용하는 프로세스 확인
sudo netstat -tulpn | grep ':80\|:443'
# 또는
sudo ss -tulpn | grep ':80\|:443'
# Traefik 서비스 확인
kubectl get svc -n kube-system traefik
Accessing through Traefik Ingress instead of a LoadBalancer is the standard approach in K3s:
# Helm으로 Ingress 포함하여 재설치
helm upgrade nginx bitnami/nginx \
--set service.type=ClusterIP \
--set ingress.enabled=true \
--set ingress.hostname=nginx.local
In this case you must connect via nginx.local, the hostname you specified. Update the /etc/hosts file or something.
Note that you can also use different ports: (not recommended)
Troubleshooting
WARNING: Kubernetes configuration file is ***-readable. This is insecure. Location: ~/.kube/config
Running related commands prints warnings like these.
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
Change the access permissions with the chmod 600 ~/.kube/config command.
See also
Favorite site
- Helm | Using Helm
- Getting closer to Kubernetes - What is Helm?
- A dreamer's story - What is kubernetes helm? - How to use helm (deploying/managing kubernetes)
- (Kubernetes) How to use Helm
- (Kubernetes) What is Helm? What is a Helm chart?
- KimDragon Tech & Economy Blog :: (DevOps) What is helm?
- (Containers) Just the essentials! Kubernetes (1) - helm package manager
- Helm or Kustomize, which to use? (Helm vs Kustomize)