Skip to content

Latest commit

 

History

History
248 lines (212 loc) · 7.13 KB

02-image-and-chart.md

File metadata and controls

248 lines (212 loc) · 7.13 KB

Add Image and Helm Chart

In this template we will add image building capabilities and a Helm chart that can be deployed to a cluster to deploy our application.

In this tutorial, we will:

  • Create a new software template with a Docker image and Helm chart,
  • Create a continuous integration pipeline to build and publish the image and chart to Github Container Registry,
  • Install the software instance we created using the new template.

You can find the final template for this tutorial in the templates/02-image-and-chart folder.

Copy the earlier template to make changes.

# We are in the template repo, i.e. {your username}/cloud-native-heroku on Github.
cp -a templates/01-hello-world templates/02-image-and-chart

Change the metadata of template.yaml

# Change for the content in templates/02-image-and-chart/template.yaml
metadata:
  name: hello-world-on-kubernetes
  title: Hello World on Kubernetes

Create a Dockerfile for our image.

# Content of templates/02-image-and-chart/skeleton/Dockerfile
FROM node:16-alpine

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install

COPY server.js .
CMD [ "node", "server.js" ]

Let's give it a try to make sure it's all tight.

# We are in the template repo, i.e. {your username}/cloud-native-heroku on Github.
docker build --tag hello:v0.1.0 templates/02-image-and-chart/skeleton
docker run -p 8080:8080 hello:v0.1.0

Visit http://127.0.0.1:8080, and you should see a page with the following because we deployed the template itself:

Hello World! My name is ${{ values.serviceName }} and my owner is ${{ values.owner }}

Let's move on to adding a Helm chart.

# We are in the template repo, i.e. {your username}/cloud-native-heroku on Github.
mkdir -p templates/02-image-and-chart/skeleton/chart

It will have chart metadata and basic Deployment and Service definitions.

# We are in the template repo, i.e. {your username}/cloud-native-heroku on Github.
mkdir -p templates/02-image-and-chart/skeleton/chart/templates

As you will notice, we need to use {% raw %} to open and {% endraw %} to close what Backstage shouldn't touch so that Helm templates are not considered.

# Content of templates/02-image-and-chart/skeleton/chart/Chart.yaml
apiVersion: v2
name: ${{ values.githubRepositoryName }}-chart
description: A Helm chart for ${{ values.serviceName }} owned by ${{ values.owner }}
type: application
version: 0.1.0
appVersion: "1.16.0"
# Content of templates/02-image-and-chart/skeleton/chart/values.yaml
image:
  # To be replaced in-place before publishing or installation.
  tag: "%%TAG%%"
# Content of templates/02-image-and-chart/skeleton/chart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: hello-world
spec:
  selector:
    app: hello-world
  ports:
    - name: http
      port: 80
      targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
        - name: hello-world
          image: ghcr.io/${{ values.githubRepositoryOrg }}/${{ values.githubRepositoryName }}:{% raw %}{{ .Values.image.tag }}{% endraw %}
          ports:
            - name: http
              containerPort: 8080

Now we will add a .github folder that will contain Github Actions workflow to build the image and Helm chart as OCI image, and then push both to Github Container Registry (GHCR).

Create the following file in .github/workflows/ci.yaml

# We are in the template repo, i.e. {your username}/cloud-native-heroku on Github.
mkdir -p templates/02-image-and-chart/skeleton/.github/workflows
# Content of templates/02-image-and-chart/skeleton/.github/workflows/ci.yaml
{% raw %}
name: Continuous Integration

on:
  push:
    branches: ['main']

jobs:
  ci:
    runs-on: ubuntu-20.04
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Setup QEMU
        uses: docker/setup-qemu-action@v1
        with:
          platforms: arm64

      - name: Setup Docker Buildx
        id: buildx
        uses: docker/setup-buildx-action@v2

      - name: Log in to Github Container Registry
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ghcr.io/${{ github.repository }}

      - name: Build and push Docker image
        id: build-push
        uses: docker/build-push-action@v3
        with:
          builder: ${{ steps.buildx.outputs.name }}
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: linux/amd64,linux/arm64
      
      - name: Update the image tag in Helm chart
        env:
          IMAGE_TAG: ${{ github.sha }}
        run: sed -i "s|%%TAG%%|${IMAGE_TAG}|g" chart/values.yaml

      - name: Install Helm
        uses: azure/setup-helm@v3
        with:
          version: 'v3.10.0'

      - name: Publish Helm chart to GHCR
        env:
          IMAGE_BASE_URL: ghcr.io/${{ github.repository_owner }}
        run: |
          helm package chart --version 9.9.9
          helm push $(find . -iname '*-chart-9.9.9.tgz') oci://${IMAGE_BASE_URL}
{% endraw %}

Once all done, create a new commit and push it.

# We are in the template repo, i.e. {your username}/cloud-native-heroku on Github.
git add .
git commit -s -m "templates: add 02-image-and-chart"
git push

Add our new template to Backstage in http://127.0.0.1:7007/catalog-import by providing the path to our new template.yaml file in Github.

https://github.com/muvaf/cloud-native-heroku/blob/main/templates/02-image-and-chart/template.yaml

Go back to creation page and try out our new software template by creating a new software instance in http://127.0.0.1:7007/create.

Once Backstage is done, you should see a Github Action your new repo running and it will result in two container images pushed in the new GitHub repository.

Github packages example

Well, let's give it a try!

Click on the chart package and get the full image path to install with Helm.

# Do not forget to change the path to your own chart image, i.e. "ghcr.io/{github user}/{repo}-chart"
helm -n testing install helloworld oci://ghcr.io/muvaf/muvaf-kubecon-testing-chart --version 9.9.9 --create-namespace --wait
kubectl get pods -n testing
kubectl get services -n testing
kubectl port-forward --namespace=testing svc/hello-world 8080:80

If you see the usual page on 127.0.0.1:8080, congrats! 🎉

Clean up.

kubectl delete namespace testing

Jump to the next tutorial that will add a continuous delivery pipeline to our software instance using ArgoCD.