.kubeconfig
in your GitHub repo, and trigger the kubectl
commands from the CI/CD job.npm version patch
git push --follow-tags
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
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" ]
.kubeconfig
files 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 push
DEV_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/kubectl@v2.0.0
with:
config: ${{ secrets.DEV_KUBECONFIG }}
command: apply -n tutorial -f ./k8s/dev_deployment.yaml
Dockerfile
, 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..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/kubectl@v2.0.0
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
26 | |
24 | |
21 | |
13 | |
11 | |
9 | |
9 | |
8 | |
8 | |
8 |