Optimizing Your Container Registry: Pushing Helm Charts to AWS ECR
Traditionally we have used container registries to store only container images, but they offers much more than that. Let's explore in this blog.
We have always used container registries like AWS ECR, Docker Hub, etc. to host our container images but did you know you can also push other artifacts like Helm Charts to your favorite registry?
Let's learn how can we do that with AWS ECR.
Bonus! - Along with AWS ECR, we will also explore how we can use Docker Hub to host our helm charts.
Containers and OCI
Containers have transformed the landscape of modern software development and deployment, enabling faster and more reliable shipping of software. Organizations are running containers at a massive scale.
Back when containerization was new, evolving, and getting popular following Docker's release, a large community emerged and started developing new container runtimes to solve their needs.
To solve the issue of incompatibility between different runtimes and image formats, the community formed Open Container Initiative(OCI).
"The Open Container Initiative (OCI) is a lightweight, open governance structure (project), formed under the auspices of the Linux Foundation, for the express purpose of creating open industry standards around container formats and runtimes. The OCI was launched on June 22nd 2015 by Docker*,* CoreOS and other leaders in the container industry."
Currently, it defines three specifications:
OCI Runtime Specification
A technical specification developed by the Open Container Initiative (OCI) that defines the configuration and lifecycle of containers at the runtime level.
Includes various aspects like :
Container Filesystem
Container Lifecycle
Container Processes
Container Configuration
Container Security
More info here: https://github.com/opencontainers/runtime-spec
OCI Image Specification
A technical specification developed by the Open Container Initiative (OCI) that defines the format and structure of container images.
It includes various aspects like :
Image Layout
Layers
Image Manifest
Image Configuration
Image References
More info here: https://github.com/opencontainers/image-spec
OCI Distribution Specification
It defines an API protocol to facilitate and standardize the distribution of content.
More info here: https://github.com/opencontainers/distribution*-spec*
"This is designed generically enough to be leveraged as a distribution mechanism for any type of content. The format of uploaded manifests, for example, need not necessarily adhere to the OCI Image Format Specification so long as it references the blobs which comprise a given artifact."
Adoption
You can find various popular container runtimes that have adopted OCI standards, for example:
One of the benefits of having a standard like OCI is that it ensures that containers created using different container runtimes and tools can be easily shared and executed across different environments.
Enough with the theories and blah blah blah...Let's jump right into the action!
Push your Helm chart to ECR
Prerequisites
Creating a Helm Chart
Let's create a helm chart from scratch using helm cli
helm create my-chart-for-ecr
it's a standard command which will generate a basic helm chart (which basically deploys an NGINX server.)
Let's read the content of
Chart.yaml
cat my-chart-for-ecr/Chart.yaml
apiVersion: v2 name: my-chart-for-ecr description: A Helm chart for Kubernetes # A chart can be either an 'application' or a 'library' chart. # # Application charts are a collection of templates that can be packaged into versioned archives # to be deployed. # # Library charts provide useful utilities or functions for the chart developer. They're included as # a dependency of application charts to inject those utilities and functions into the rendering # pipeline. Library charts do not define any templates and therefore cannot be deployed. type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) version: 0.1.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. appVersion: "1.16.0"
Note that version of this helm chart is
0.1.0
Let's package (packages a chart into a versioned chart archive file) the chart so we can push it.
helm package ./my-chart-for-ecr/
Output :
Preparing ECR
Create a Repo in ECR for our use
aws ecr create-repository \ --repository-name my-chart-for-ecr \ --region us-east-1 # change region as per your need
Getting Creds for ECR Authorization
Authenticate your Helm client for our ECR
aws ecr get-login-password \ --region us-east-1 | helm registry login \ --username AWS \ --password-stdin AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com
Pushing Helm Chart to the ECR
- Push the chart using helm CLI.
helm push my-chart-for-ecr-0.1.0.tgz oci://AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/
- Describe your Helm chart.
aws ecr describe-images \
--repository-name my-chart-for-ecr \
--region us-east-1
Output :
let's observe it in AWS Console > ECR
Using Helm Chart hosted on AWS ECR
Login to AWS ECR and Authenticate your helm client. (Just like we did in the above step.)
aws ecr get-login-password \ --region us-east-1 | helm registry login \ --username AWS \ --password-stdin AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com
Install the helm chart (
--dry-run
to see the output)helm install chart-from-ecr oci://AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/my-chart-for-ecr --version 0.1.0 --dry-run
Output:
Pulled: 333333333333.dkr.ecr.us-east-1.amazonaws.com/my-chart-for-ecr:0.1.0
Digest: sha256:5b14b2094ab4581a74ed2bc036993da6cdee10c06cd463027a50f2b227ebf7da
NAME: chart-from-ecr
LAST DEPLOYED: Sat Jun 3 12:04:42 2023
NAMESPACE: crafto
STATUS: pending-install
REVISION: 1
HOOKS:
---
# Source: my-chart-for-ecr/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "chart-from-ecr-my-chart-for-ecr-test-connection"
labels:
helm.sh/chart: my-chart-for-ecr-0.1.0
app.kubernetes.io/name: my-chart-for-ecr
app.kubernetes.io/instance: chart-from-ecr
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['chart-from-ecr-my-chart-for-ecr:80']
restartPolicy: Never
MANIFEST:
---
# Source: my-chart-for-ecr/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: chart-from-ecr-my-chart-for-ecr
labels:
helm.sh/chart: my-chart-for-ecr-0.1.0
app.kubernetes.io/name: my-chart-for-ecr
app.kubernetes.io/instance: chart-from-ecr
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
---
# Source: my-chart-for-ecr/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: chart-from-ecr-my-chart-for-ecr
labels:
helm.sh/chart: my-chart-for-ecr-0.1.0
app.kubernetes.io/name: my-chart-for-ecr
app.kubernetes.io/instance: chart-from-ecr
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: my-chart-for-ecr
app.kubernetes.io/instance: chart-from-ecr
---
# Source: my-chart-for-ecr/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: chart-from-ecr-my-chart-for-ecr
labels:
helm.sh/chart: my-chart-for-ecr-0.1.0
app.kubernetes.io/name: my-chart-for-ecr
app.kubernetes.io/instance: chart-from-ecr
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: my-chart-for-ecr
app.kubernetes.io/instance: chart-from-ecr
template:
metadata:
labels:
app.kubernetes.io/name: my-chart-for-ecr
app.kubernetes.io/instance: chart-from-ecr
spec:
serviceAccountName: chart-from-ecr-my-chart-for-ecr
securityContext:
{}
containers:
- name: my-chart-for-ecr
securityContext:
{}
image: "nginx:1.16.0"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{}
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace crafto -l "app.kubernetes.io/name=my-chart-for-ecr,app.kubernetes.io/instance=chart-from-ecr" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace crafto $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace crafto port-forward $POD_NAME 8080:$CONTAINER_PORT
So Yes! ๐ ๐ ๐ We were able to see all the manifest this helm chart was going to install.
[Bonus] Push your Helm chart to DockerHub
Let's continue from the part where we ran the
helm package
Log in to Docker Hub using your Helm client.
helm registry login registry-1.docker.io -u DOCKERHUB_USERNAME
Push your chart to a DockerHub.
helm push my-chart-for-ecr-0.1.0.tgz oci://registry-1.docker.io/DOCKERHUB_USERNAME
This will create a docker repository called
my-chart-for-ecr
in your DockerHub account. (Image would beDOCKERHUB_USERNAME/my-chart-for-ecr
)
Note - we are able to push/host our helm charts to our same old container registries because Helm Chart is another OCI artifact! (see reference links for more info)
Final words
This was just a way to store your helm charts on ECR / Docker Hub or any other OCI-compliant repositories. You can version control this (either with your services or in a separate repo) and also set up some CI/CD pipeline with some automated testing(maybe using k3s/kind to spin a temp local k8s cluster and to test deploying your helm chart there) to achieve a complete lifecycle of your helm chart, just like a regular software project.
Thank you so much for being here! Have a nice one and see you in the next blog.
References
https://docs.docker.com/docker-hub/oci-artifacts/#using-oci-artifacts-with-docker-hub
https://helm.sh/docs/topics/registries/#using-an-oci-based-registry
https://docs.aws.amazon.com/AmazonECR/latest/userguide/push-oci-artifact.html
https://docs.aws.amazon.com/AmazonECR/latest/userguide/ECR_on_EKS.html#using-helm-charts-eks