Kubernetes is an amazing technology for managing large scale distributed applications. Its YAML configuration files make it easy to tune an application to fit your needs but Kubernetes has a lot of different objects and therefor a lot of different configuration files to maintain. For example, a production application could have a Deployment, Service, Secret, Config Map and Persistent Volume Claim for each of its components such as a Web App, API, Database, bot, etc. This is a lot of configuration files to maintain and they would be difficult to package if you are building an application which users need to download and run in their own environment. This is where Helm Charts come in to the picture, they group all of the configuration files needed to run an application into a single package called a Chart
. Helm Charts templatize the configuration files, allow you to manage them with a global configuration and make it easy to publish your entire infrastructure as a single package. Lets take a look at some examples of using and building helm charts.
💡 Refer to Kubernetes Quick Start Guide ☁️⚡️🚀 for an in-depth Kubernetes tutorial
Using Helm Charts
Make sure you have Minikube setup and running and install Helm. After helm is installed we need to add a helm chart repository. Artifact Hub can be referenced to find helm repositories. A popular repository which offers production grade version of most of the popular open source applications is Bitnami.
Add the Bitnami repository and run the helm repo update
command to make sure we have the latest versions.
$ helm repo add bitnami https://charts.bitnami.com/bitnami
"bitnami" has been added to your repositories
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "bitnami" chart repository
Update Complete. ⎈Happy Helming!⎈
Search the configured helm repositories to look for applications we may want to use, in this case search for a Redis chart.
$ helm search repo redis
NAME CHART VERSION APP VERSION DESCRIPTION
bitnami/redis 18.2.0 7.2.2 Redis(R) is an open source, advanced key-value ...
bitnami/redis-cluster 9.0.13 7.2.2 Redis(R) is an open source, scalable, distribut...
💡 The full details of helm charts can be referenced in their associated GitHub Repository.
Install the standard Redis chart.
$ helm install mydb bitnami/redis
NAME: mydb
LAST DEPLOYED: Mon Oct 30 07:43:01 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: redis
CHART VERSION: 18.2.0
APP VERSION: 7.2.2
** Please be patient while the chart is being deployed **
Redis® can be accessed on the following DNS names from within your cluster:
mydb-redis-master.default.svc.cluster.local for read/write operations (port 6379)
mydb-redis-replicas.default.svc.cluster.local for read-only operations (port 6379)
To get your password run:
export REDIS_PASSWORD=$(kubectl get secret --namespace default mydb-redis -o jsonpath="{.data.redis-password}" | base64 -d)
To connect to your Redis® server:
1. Run a Redis® pod that you can use as a client:
kubectl run --namespace default redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image docker.io/bitnami/redis:7.2.2-debian-11-r0 --command -- sleep infinity
Use the following command to attach to the pod:
kubectl exec --tty -i redis-client \
--namespace default -- bash
2. Connect using the Redis® CLI:
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h mydb-redis-master
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h mydb-redis-replicas
To connect to your database from outside the cluster execute the following commands:
kubectl port-forward --namespace default svc/mydb-redis-master 6379:6379 &
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h 127.0.0.1 -p 6379
Verify the helm chart is deployed and Redis is running on the Kubernetes cluster.
$ helm ls
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
mydb default 1 2023-10-30 07:43:01.730917 -0400 EDT deployed redis-18.2.0 7.2.2
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/mydb-redis-master-0 1/1 Running 0 4m4s
pod/mydb-redis-replicas-0 1/1 Running 0 4m4s
pod/mydb-redis-replicas-1 1/1 Running 0 3m23s
pod/mydb-redis-replicas-2 1/1 Running 0 3m1s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d22h
service/mydb-redis-headless ClusterIP None <none> 6379/TCP 4m4s
service/mydb-redis-master ClusterIP 10.106.79.115 <none> 6379/TCP 4m4s
service/mydb-redis-replicas ClusterIP 10.106.46.152 <none> 6379/TCP 4m4s
NAME READY AGE
statefulset.apps/mydb-redis-master 1/1 4m4s
statefulset.apps/mydb-redis-replicas 3/3 4m4s
Follow the post installation prompt and verify that Redis is working correctly.
$ export REDIS_PASSWORD=$(kubectl get secret --namespace default mydb-redis -o jsonpath="{.data.redis-password}" | base64 -d)
$ kubectl run --namespace default redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image docker.io/bitnami/redis:7.2.2-debian-11-r0 --command -- sleep infinity
pod/redis-client created
$ kubectl exec --tty -i redis-client --namespace default -- bash
I have no name!@redis-client:/$ REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h mydb-redis-master
mydb-redis-master:6379> SET key value
OK
mydb-redis-master:6379> GET key
"value"
Helm charts are a great way to run popular applications like Databases since the helm chart implements many of the best practices for you and allows you to just provide higher level tuning.
Delete the Redis helm chart.
$ helm delete mydb
release "mydb" uninstalled
$ helm ls
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
Helm utilizes a values.yaml
file for its configuration, here is the Bitnami Redis values.yaml as a reference and a custom values.yaml
file can be passed to the helm install
command to override any of the values.
Create a custom values.yaml
file to override the password and replica count.
📝 values.yaml
auth:
password: myDbSecret123
replica:
replicaCount: 4
Install Redis again but now pass in the updated configuration.
$ helm install mydb bitnami/redis -f values.yaml
NAME: mydb
LAST DEPLOYED: Tue Oct 31 06:57:24 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: redis
CHART VERSION: 18.2.0
APP VERSION: 7.2.2
** Please be patient while the chart is being deployed **
Redis® can be accessed on the following DNS names from within your cluster:
mydb-redis-master.default.svc.cluster.local for read/write operations (port 6379)
mydb-redis-replicas.default.svc.cluster.local for read-only operations (port 6379)
To get your password run:
export REDIS_PASSWORD=$(kubectl get secret --namespace default mydb-redis -o jsonpath="{.data.redis-password}" | base64 -d)
To connect to your Redis® server:
1. Run a Redis® pod that you can use as a client:
kubectl run --namespace default redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image docker.io/bitnami/redis:7.2.2-debian-11-r0 --command -- sleep infinity
Use the following command to attach to the pod:
kubectl exec --tty -i redis-client \
--namespace default -- bash
2. Connect using the Redis® CLI:
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h mydb-redis-master
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h mydb-redis-replicas
To connect to your database from outside the cluster execute the following commands:
kubectl port-forward --namespace default svc/mydb-redis-master 6379:6379 &
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h 127.0.0.1 -p 6379
Validate that the new configuration has been applied correctly, you should see the new password set in the secret and 4 replicas running.
$ helm ls
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
mydb default 1 2023-10-31 06:57:24.661346 -0400 EDT deployed redis-18.2.0 7.2.2
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/mydb-redis-master-0 1/1 Running 0 3m51s
pod/mydb-redis-replicas-0 1/1 Running 0 3m51s
pod/mydb-redis-replicas-1 1/1 Running 0 3m16s
pod/mydb-redis-replicas-2 1/1 Running 0 2m51s
pod/mydb-redis-replicas-3 1/1 Running 0 2m30s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d21h
service/mydb-redis-headless ClusterIP None <none> 6379/TCP 3m51s
service/mydb-redis-master ClusterIP 10.102.17.165 <none> 6379/TCP 3m51s
service/mydb-redis-replicas ClusterIP 10.111.189.75 <none> 6379/TCP 3m51s
NAME READY AGE
statefulset.apps/mydb-redis-master 1/1 3m51s
statefulset.apps/mydb-redis-replicas 4/4 3m51s
$ echo $(kubectl get secret --namespace default mydb-redis -o jsonpath="{.data.redis-password}" | base64 -d)
myDbSecret123
$ helm delete mydb
release "mydb" uninstalled
Helm also allows you to override values by passing them in with the --set
flag which can be used to pass in sensitive values such as secrets. In production this method is used to set the secrets of a helm chart using environment variables within the CI/CD Pipeline.
💡 Refer to DevOps CI/CD Quick Start Guide with GitHub Actions 🛠️🐙⚡️ for a Guide on creating CI/CD Pipelines
Remove the password from the values.yaml
file.
📝 values.yaml
replica:
replicaCount: 4
Now pass in the password from the command line with the --set
flag.
$ helm install mydb bitnami/redis --set auth.password=myDbSecret123 -f values.yaml
NAME: mydb
LAST DEPLOYED: Tue Oct 31 07:10:39 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: redis
CHART VERSION: 18.2.0
APP VERSION: 7.2.2
** Please be patient while the chart is being deployed **
Redis® can be accessed on the following DNS names from within your cluster:
mydb-redis-master.default.svc.cluster.local for read/write operations (port 6379)
mydb-redis-replicas.default.svc.cluster.local for read-only operations (port 6379)
To get your password run:
export REDIS_PASSWORD=$(kubectl get secret --namespace default mydb-redis -o jsonpath="{.data.redis-password}" | base64 -d)
To connect to your Redis® server:
1. Run a Redis® pod that you can use as a client:
kubectl run --namespace default redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image docker.io/bitnami/redis:7.2.2-debian-11-r0 --command -- sleep infinity
Use the following command to attach to the pod:
kubectl exec --tty -i redis-client \
--namespace default -- bash
2. Connect using the Redis® CLI:
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h mydb-redis-master
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h mydb-redis-replicas
To connect to your database from outside the cluster execute the following commands:
kubectl port-forward --namespace default svc/mydb-redis-master 6379:6379 &
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h 127.0.0.1 -p 6379
Verify the password has been set correctly then delete the chart.
$ echo $(kubectl get secret --namespace default mydb-redis -o jsonpath="{.data.redis-password}" | base64 -d)
myDbSecret123
$ helm delete mydb
release "mydb" uninstalled
Nice! This is the basics for using helm charts and there are charts available for nearly every popular application, this gives us a simple way to get production grade instances of them running. Now lets take a look at creating a Kubernetes application.
App with K8s configuration files
⭐️ The complete source code referenced in this guide is available on GitHub
https://github.com/dpills/helm-quick-start
Application setup
Create a small FastAPI app which will use a secret static token to authenticate the endpoint.
💡 Refer to FastAPI Production Setup Guide 🏁⚡️🚀 for a full Python FastAPI Guide
Install the necessary dependencies with Poetry.
📝 pyproject.toml
[tool.poetry]
name = "helm-api"
version = "0.1.0"
description = ""
authors = ["dpills"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.11"
fastapi = "^0.104.1"
uvicorn = { extras = ["standard"], version = "^0.23.2" }
pydantic-settings = "^2.0.3"
[tool.poetry.group.dev.dependencies]
ruff = "^0.1.3"
black = "^23.10.1"
mypy = "^1.6.1"
[tool.black]
line-length = 88
[tool.ruff]
select = ["E", "F", "I"]
fixable = ["ALL"]
exclude = [".git", ".mypy_cache", ".ruff_cache"]
line-length = 88
[tool.mypy]
disallow_any_generics = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true
strict_equality = true
disallow_untyped_decorators = false
ignore_missing_imports = true
implicit_reexport = true
plugins = "pydantic.mypy"
[tool.pydantic-mypy]
init_forbid_extra = true
init_typed = true
warn_required_dynamic_aliases = true
warn_untyped_fields = true
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
$ poetry install
Installing dependencies from lock file
No dependencies to install or update
Create the API code.
📝 main.py
import uvicorn
from fastapi import FastAPI, HTTPException, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from pydantic import BaseModel
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
static_token: str
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
settings = Settings()
app = FastAPI()
security = HTTPBearer()
class Data(BaseModel):
item: str
@app.get("/data", response_model=Data)
async def get_data(
access_token: HTTPAuthorizationCredentials = Security(security),
) -> Data:
"""
Get Data
"""
if access_token.credentials != settings.static_token:
raise HTTPException(status_code=401, detail="Unauthorized")
return Data(item="helm")
if __name__ == "__main__":
uvicorn.run(
"main:app",
host="0.0.0.0",
port=8000,
log_level="debug",
reload=True,
)
Add a .env
file for local testing.
📝 .env
STATIC_TOKEN=MY_SECRET_TOKEN_123
Make sure the API is working as expected locally, it should only allow the API call to be made when the secret static token is sent in the Authorization Bearer token header.
$ poetry run python3 main.py
INFO: Will watch for changes in these directories: ['/Users/dpills/articles/helm-quick-start/api']
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO: Started reloader process [13765] using WatchFiles
INFO: Started server process [13771]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: 127.0.0.1:51135 - "GET /data HTTP/1.1" 403 Forbidden
INFO: 127.0.0.1:51136 - "GET /data HTTP/1.1" 200 OK
$ curl -v http://localhost:8000/data
< HTTP/1.1 403 Forbidden
{"detail":"Not authenticated"}
$ curl -v http://localhost:8000/data -H 'Authorization: Bearer MY_SECRET_TOKEN_123'
< HTTP/1.1 200 OK
{"item":"helm"}
Now that we know it is working as expected, containerize it with a Dockerfile
.
📝 Dockerfile
FROM python:3.11-slim-bookworm as requirements-stage
RUN pip install poetry
COPY ./pyproject.toml ./poetry.lock /
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes --without=dev
FROM python:3.11-slim-bookworm
COPY --from=requirements-stage /requirements.txt /requirements.txt
COPY ./app /app
RUN python3 -m pip install --no-cache-dir --upgrade -r requirements.txt
EXPOSE 8000
ENTRYPOINT ["uvicorn", "--host", "0.0.0.0", "--port", "8000", "main:app"]
💡 Refer to Containers Demystified 🐳🤔 for a Docker container guide
Build and push the container image to Docker Hub.
$ docker build . -t dpills/helm-api:v1.0.0 --push
[+] Building 40.7s (13/13) FINISHED docker:desktop-linux
...
=> [requirements-stage 2/4] RUN pip install poetry 19.6s
=> [requirements-stage 3/4] COPY ./pyproject.toml ./poetry.lock / 0.0s
=> [requirements-stage 4/4] RUN poetry export -f requirements.txt --output requirements.txt --w 0.5s
=> [stage-1 2/4] COPY --from=requirements-stage /requirements.txt /requirements.txt 0.0s
=> [stage-1 3/4] COPY ./main.py /main.py 0.0s
=> [stage-1 4/4] RUN python3 -m pip install --no-cache-dir --upgrade -r requirements.txt 6.4s
...
=> => naming to docker.io/dpills/helm-api:v1.0.0 0.0s
=> pushing dpills/helm-api:v1.0.0 with docker 11.2s
Standard Kubernetes Configuration
Now that we have our application container image built, we need to create the Kubernetes configuration files to deploy it.
Create a secret for our STATIC_TOKEN
environment variable.
📝 k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: helm-guide-api-secret
data:
STATIC_TOKEN: TVlfU0VDUkVUX1RPS0VOXzEyMw==
💡 This can be generated from the
.env
file withkubectl
. Secret files are just base64 encodings of the values.$ kubectl create secret generic helm-guide-api-secret --from-env-file=.env --dry-run=client -o yaml apiVersion: v1 data: STATIC_TOKEN: TVlfU0VDUkVUX1RPS0VOXzEyMw== kind: Secret metadata: creationTimestamp: null name: helm-guide-api-secret $ echo TVlfU0VDUkVUX1RPS0VOXzEyMw== | base64 -d MY_SECRET_TOKEN_123
Create a deployment with the new API container image and map the secret to the environment variables.
📝 k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: helm-guide-api
name: helm-guide-api
spec:
replicas: 1 # One Instance
selector:
matchLabels:
app: helm-guide-api
template:
metadata:
labels:
app: helm-guide-api
spec:
containers:
- name: helm-guide-api
image: dpills/helm-api:v1.0.0 # API Image
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8000
protocol: TCP
envFrom:
- secretRef:
name: helm-guide-api-secret # Secret Mapping
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: "1"
memory: 1Gi
Finally, create a service to expose the API.
📝 k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: helm-guide-api
name: helm-guide-api-svc
spec:
ports:
- name: http
port: 8000
protocol: TCP
targetPort: 8000
selector:
app: helm-guide-api
Apply the Kubernetes configuration.
$ kubectl apply -f k8s
deployment.apps/helm-guide-api created
secret/helm-guide-api-secret created
service/helm-guide-api-svc created
Connect to the service with Minikube.
$ minikube service helm-guide-api-svc --url
😿 service default/helm-guide-api-svc has no node port
http://127.0.0.1:51476
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
Validate it is working as expected with the exposed Minikube port from the last command.
$ curl -v http://localhost:51476/data
< HTTP/1.1 403 Forbidden
{"detail":"Not authenticated"}
$ curl -v http://localhost:51476/data -H 'Authorization: Bearer MY_SECRET_TOKEN_123'
< HTTP/1.1 200 OK
{"item":"helm"}
Awesome! this is great but if we look at the Kubernetes configuration files we can see that the root application name helm-guide-api
needs to be constantly referenced throughout the configuration and there is a lot of boilerplate which will never change. The main items we will update often will be the image version and potentially replica count. Also with following Infrastructure as Code (IaC) best practices and committing all of our configuration files, we are exposing our application secret. Being able to template these files and create variables for the portions that we need to change or keep secret is what Helm allows us to do.
App with a Helm Chart
Create the new helm chart with the helm create
command. You can take a look at the default bootstrapped helm chart example created by this command to see a lot of the functionality which we will not fully cover in this article.
$ helm create infra
Creating infra
Update the Chart.yaml
with a description and version.
📝 infra/Chart.yaml
apiVersion: v2
name: helm-guide-api
description: Helm API
type: application
version: 1.0.0
appVersion: "1.0.0"
Now delete all of the bootstrapped files in the templates
folder and copy the deployment.yaml
, service.yaml
and secret.yaml
configuration files into the templates
folder.
The file structure should look like this.
Update the service to use the helm release name for the application name using the double curly brace helm templating syntax.
📝 infra/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: {{ .Release.Name }}
name: {{ .Release.Name }}-svc
spec:
ports:
- name: http
port: 8000
protocol: TCP
targetPort: 8000
selector:
app: {{ .Release.Name }}
For the deployment file we need to pass in the replica count and container image and as we saw in the start of this article the values.yaml
file is used to pass in values. Update the values.yaml
file with an API configuration defining these two values.
📝 infra/values.yaml
api:
image: dpills/helm-api:v1.0.0
replicas: 1
Update the deployment template to use the release name, api image and replica count. For the replica count, cast the type to make sure it is an integer.
📝 infra/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: {{ .Release.Name }}
name: {{ .Release.Name }}
spec:
replicas: {{ int .Values.api.replicas }}
selector:
matchLabels:
app: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
containers:
- name: {{ .Release.Name }}
image: {{ .Values.api.image }}
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8000
protocol: TCP
envFrom:
- secretRef:
name: {{ .Release.Name }}-secret
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: "1"
memory: 1Gi
For the secret we need to pass in the static token and base64 encode it but we should not commit the secret to our source code. Add an entry will a null
value to the values.yaml
file which will be passed in with the helm install --set
flag.
📝 infra/values.yaml
api:
image: dpills/helm-api:v1.0.0
replicas: 1
static_token: null # Pass this in with --set static_token=XXX
Update the secret to to use the release name, validate that a static token value has been passed in with the required
keyword and base64 encode it by piping to the b64enc
function.
📝 infra/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: {{ .Release.Name }}-secret
data:
STATIC_TOKEN: {{ required "A static token is required" .Values.api.static_token | b64enc }}
The NOTES.txt
is what is printed out after installing the chart, update this to some simple text for this example.
📝 infra/templates/NOTES.txt
Helm API Example!
This should now be fully setup, delete the standard Kubernetes configuration deployment if it is still running and run the application with the helm chart instead.
$ kubectl delete -f k8s
deployment.apps "helm-guide-api" deleted
secret "helm-guide-api-secret" deleted
service "helm-guide-api-svc" deleted
$ helm install helm-api ./infra --set api.static_token=MY_SECRET_TOKEN_123
NAME: helm-api
LAST DEPLOYED: Wed Nov 1 08:44:37 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Helm API Example!
Validate the application is working as expected.
$ helm ls
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
helm-api default 1 2023-11-01 08:44:37.222599 -0400 EDT deployed helm-guide-api-1.0.0 1.0.0
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/helm-api-79877dcfc6-8rv47 1/1 Running 0 61s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/helm-api-svc ClusterIP 10.109.109.197 <none> 8000/TCP 61s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d23h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/helm-api 1/1 1 1 61s
NAME DESIRED CURRENT READY AGE
replicaset.apps/helm-api-79877dcfc6 1 1 1 61s
$ minikube service helm-api-svc --url
😿 service default/helm-api-svc has no node port
http://127.0.0.1:51778
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
$ curl -v http://localhost:51778/data
< HTTP/1.1 403 Forbidden
{"detail":"Not authenticated"}
$ curl -v http://localhost:51778/data -H 'Authorization: Bearer MY_SECRET_TOKEN_123'
< HTTP/1.1 200 OK
{"item":"helm"}
Congrats you just created a helm chart! 🎉 We can see that the release name that we passed in to the helm install command has been used for all of the object names. The primary configuration file is greatly simplified with the values.yaml
file and our secret configuration is committed to our source code but the sensitive value is no longer exposed. The Helm Chart Documentation can be referenced for a full overview of the syntax and features. Utilizing helm charts to manage Kubernetes applications has been very useful for me and I hope this guide helps you build your next amazing application! 😊
Top comments (1)
Very nice! I did a couple of things differently.
1) in the Docker file used the line
COPY main.py /
2) used port forwarding to get to the service:
kubectl port-forward service/helm-api-svc 8001:8000