
The stages of the sample project
.kubeconfig in your GitHub repo, and trigger the kubectl commands from the CI/CD job.npm version patch
git push --follow-tags
Your dev deployment process could be as easy as this.
server.js) is straightforward and starts an HTTP server that returns a hello world message when called.'use strict';
const express = require('express');
const version = "version is in development"
const app = express();
app.get('/', (_, res) => {
res.send(`Hello SAP Tech Bytes! This ${version}`);
});
app.listen(process.env.PORT || 3000, () => {
console.log(`Started on port ${process.env.PORT || 3000}`);
});package.json descriptor lists the usual properties and the dependencies of the project. As we don't need a big test suite for this small server, I only added a "placeholder test" that is always successful.{
"name": "tech-bytes_kyma-cicd",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js",
"build": "node buildScript.js",
"test": "echo \"Success\" "
},
"dependencies": {
"express": "^4.16.1",
"replace-in-file": "^6.2.0"
}
}build script in this file. During the build step, buildScript.js will replace the fixed string in the application with the current version string. You probably won’t do this in your app and instead call cds build or a similar command here.const replace = require("replace-in-file");
const pkg = require("./package.json");
try {
replace.sync({
files: "server.js",
from: [/version is in development/g],
to: [`is version ${pkg.version}`],
});
}
catch (error) {
console.error("Error occurred:", error);
}npm install
npm start
Running on localhost.
Dockerfile will do this for you.FROM node:14-alpine
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./
RUN npm install
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "node", "server.js" ].kubeconfigfiles from the Kyma console expire after eight hours. It would cause many problems in your CI/CD pipeline if there weren't an alternative. Luckily there is one: Creating a Kyma service account. This tutorial shows you how to create a.kubeconfig for a service account that doesn't expire.k8s/dev_deployment.yaml descriptor:apiVersion: apps/v1
kind: Deployment
metadata:
name: tech-bytes
spec:
replicas: 1
selector:
matchLabels:
app: tech-bytes
template:
metadata:
labels:
app: tech-bytes
version: v1
spec:
containers:
- image: ghcr.io/<user>/<repo name>:latest REPLACE THIS LINE
imagePullPolicy: Always
name: tech-bytes
ports:
- name: http
containerPort: 3000
resources:
limits:
memory: 2000Mi
requests:
memory: 32Mi
imagePullSecrets:
- name: regcred
---
apiVersion: v1
kind: Service
metadata:
name: tech-bytes
labels:
app: tech-bytes
spec:
ports:
- port: 8080
name: http
targetPort: 3000
selector:
app: tech-bytes
---
apiVersion: gateway.kyma-project.io/v1alpha1
kind: APIRule
metadata:
name: tech-bytes
spec:
gateway: kyma-gateway.kyma-system.svc.cluster.local
service:
name: tech-bytes
port: 8080
host: tech-bytes
rules:
- path: /.*
methods: ["GET"]
accessStrategies:
- handler: noop
config: {}image tag in the file above. This tag needs to point to your GitHub user and package name.imagePullSecret "regcred". This secret is required as GitHub only allows authenticated pulls by default. Make sure you are logged in to kubectl and run the following commands to set this secret up.kubectl -n tutorial create secret docker-registry regcred --docker-server=https://ghcr.io --docker-username=<github user> --docker-password=<github personal access token>git add .
git commit -a -m "initial commit"
git pushDEV_KUBECONFIG to store the .kubeconfig next to your repository securely. Don't just drop the content of the file but make sure it's base-64-encoded.# For MAC
cat tutorial-kubeconfig.yaml | base64.github/workflows/main.yaml.name: Run Tests
on:
push:
branches:
- main
jobs:
run-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 14
- run: npm install
- run: npm test.github/workflows/deploy.yaml. This flow won't be trigger automatically and can only be executed by a button press on the GitHub website.name: Deploy Manually
# Triggered manually
on: workflow_dispatch
env:
REGISTRY: ghcr.io
IMAGE_NAME: sap-samples/tech-bytes-kyma-cicd
jobs:
deploy-to-dev:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- run: npm install
- run: npm run build
- name: Log in to the container registry
uses: docker/login-action@v1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v3
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
labels: ${{ steps.meta.outputs.labels }}
- uses: steebchen/[email protected]
with:
config: ${{ secrets.DEV_KUBECONFIG }}
command: apply -n tutorial -f ./k8s/dev_deployment.yamlDockerfile, build, and push the image to the registry. The last action will finally read the kubeconfig from the secret we created in the previous step and deploy the image to our Kyma cluster.Dockerfile. This makes sure that you use the flow and files that are defined in the respective branch.
Run a workflow from the website.

Refresh the page and click on the workflow that you now see.

You should screen a success message once the workflow is completed.

You can find the URL of the application in the Kyma console.

You will see the production build of the application when you click on the link.
.github/workflows/publish.yaml, which will be invoked on every push that contains a new tag.name: Release New Version
on:
push:
tags:
- "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
env:
REGISTRY: ghcr.io
IMAGE_NAME: sap-samples/tech-bytes-kyma-cicd
jobs:
run-tests:
runs-on: ubuntu-latest
name: Run tests
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 14
- run: npm install
- run: npm test
build-and-push-image:
needs: run-tests
name: Build and push the image
outputs:
image-tag: ${{ steps.get-image-tag.outputs.result }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v2
- run: npm install
- run: npm run build
- name: Log in to the container registry
uses: docker/login-action@v1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v3
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Get the image tag
uses: actions/github-script@v4
id: get-image-tag
with:
script: return ${{ steps.meta.outputs.json }}.tags[0]
result-encoding: string
deploy-to-dev:
needs: build-and-push-image
name: Deploy to dev
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Deploy to the dev environment
uses: steebchen/[email protected]
with:
config: ${{ secrets.DEV_KUBECONFIG }}
command: -n tutorial set image deployment/demo-app demo-app=${{needs.build-and-push-image.outputs.image-tag }}
create-release:
needs: build-and-push-image
name: Create release
runs-on: ubuntu-latest
steps:
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
npm version patch
git push --follow-tags
Notice that this push command triggered multiple workflows.

A succeeded "Release New Version" flow (this time for tag 1.0.2).

Just like magic, you now see that the deployed version has been updated. Yay!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 106 | |
| 46 | |
| 36 | |
| 26 | |
| 26 | |
| 26 | |
| 23 | |
| 22 | |
| 22 | |
| 21 |