# Optimizing Your Container Registry: Pushing Helm Charts to AWS ECR

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?

![Continue Season 9 GIF by The Office](https://media4.giphy.com/media/XXdiedv0abxEIZxkQz/giphy.gif?cid=ecf05e47x1vgnfady1hjlw1kk44j0b3o0b7m42r3wd4uzohy&ep=v1_gifs_search&rid=giphy.gif&ct=g align="center")

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](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](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\*](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:
    
    * [runC](https://github.com/opencontainers/runc) *(BTW Docker donated its runtime engine called* `runc` *to OCI)*
        
    * [crun](https://github.com/containers/crun)
        
    * [Kata](https://github.com/kata-containers/kata-containers)
        
    * [gVisor](https://github.com/google/gvisor)
        
* 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!

![homer simpson GIF](https://media4.giphy.com/media/26tjZkBbRU5QHB5Ys/giphy.gif?cid=ecf05e47m7xnvwqlc81u4smy5b3djg6jxzfbe17xh9awh9yz&ep=v1_gifs_related&rid=giphy.gif&ct=g align="center")

## Push your Helm chart to ECR

### Prerequisites

* [Helm CLI](https://helm.sh/docs/intro/install/) (v3.8.0+)
    
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
    

### Creating a Helm Chart

1. Let's create a helm chart from scratch using helm cli
    
    ```bash
    helm create my-chart-for-ecr
    ```
    
    it's a standard command which will generate a basic helm chart (which basically deploys an NGINX server.)
    
2. Let's read the content of `Chart.yaml`
    
    `cat my-chart-for-ecr/Chart.yaml`
    
    ```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`
    
3. Let's package (*packages a chart into a versioned chart archive file*) the chart so we can push it.
    
    ```bash
    helm package ./my-chart-for-ecr/
    ```
    

Output :

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685714244696/9b2c52c5-9e33-4634-8e7a-102a6dea13a3.png align="center")

### Preparing ECR

1. Create a Repo in ECR for our use
    
    ```bash
    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

1. Authenticate your Helm client for our ECR
    
    ```bash
    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

1. Push the chart using helm CLI.
    

```bash
helm push my-chart-for-ecr-0.1.0.tgz oci://AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/
```

1. Describe your Helm chart.
    

```bash
aws ecr describe-images \
     --repository-name my-chart-for-ecr \
     --region us-east-1
```

Output :

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685716796305/f4bba686-e3f5-45f1-81e6-da6bdd2f331d.png align="center")

let's observe it in AWS Console &gt; ECR

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685717139790/37b6f368-4573-45c7-808c-5b90db2f2305.png align="center")

### Using Helm Chart hosted on AWS ECR

1. Login to AWS ECR and Authenticate your helm client. (Just like we did in the above step.)
    
    ```bash
    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
    ```
    
2. Install the helm chart ( `--dry-run` to see the output)
    
    ```bash
    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:

```bash
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.

![SpongeBob gif. SpongeBob pumps his arms up and down excitedly, biting his little yellow lip.](https://media0.giphy.com/media/oF5oUYTOhvFnO/giphy.gif?cid=ecf05e47a218c93erv7ze9rcba8jp2tz7qfwjicfcdxifwig&ep=v1_gifs_search&rid=giphy.gif&ct=g align="center")

## \[Bonus\] Push your Helm chart to DockerHub

1. Let's continue from the part where we ran the `helm package`
    
2. Log in to Docker Hub using your Helm client.
    
    ```bash
    helm registry login registry-1.docker.io -u DOCKERHUB_USERNAME
    ```
    
3. Push your chart to a DockerHub.
    
    ```bash
    helm push my-chart-for-ecr-0.1.0.tgz oci://registry-1.docker.io/DOCKERHUB_USERNAME
    ```
    
4. This will create a docker repository called `my-chart-for-ecr` in your DockerHub account. (Image would be `DOCKERHUB_USERNAME/my-chart-for-ecr`)
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685799367310/4a97ea57-b324-4e13-bba0-fc6fc71f2c03.png align="center")
    

**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](https://github.com/k3s-io/k3s)/[kind](https://github.com/kubernetes-sigs/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.

![Season 9 Nbc GIF by The Office](https://media0.giphy.com/media/xaLjIV9qDtnvrh76NF/giphy.gif?cid=ecf05e47x1vgnfady1hjlw1kk44j0b3o0b7m42r3wd4uzohy&ep=v1_gifs_search&rid=giphy.gif&ct=g align="center")

---

## References

1. [https://docs.docker.com/docker-hub/oci-artifacts/#using-oci-artifacts-with-docker-hub](https://docs.docker.com/docker-hub/oci-artifacts/#using-oci-artifacts-with-docker-hub)
    
2. [https://helm.sh/docs/topics/registries/#using-an-oci-based-registry](https://helm.sh/docs/topics/registries/#using-an-oci-based-registry)
    
3. [https://docs.aws.amazon.com/AmazonECR/latest/userguide/push-oci-artifact.html](https://docs.aws.amazon.com/AmazonECR/latest/userguide/push-oci-artifact.html)
    
4. [https://docs.aws.amazon.com/AmazonECR/latest/userguide/ECR\_on\_EKS.html#using-helm-charts-eks](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ECR_on_EKS.html#using-helm-charts-eks)
