GitOps to Configure Kong: How to Set Up GitHub Actions Using decK
Kong’s fast, lightweight and scalable API management solution helps improve developer productivity by automating the delivery of API management. One way Kong automates API management is through a continuous integration and continuous delivery (CI/CD) process by leveraging Kong's decK (declarative configuration for Kong) and GitHub Actions.
Kong's decK provides a command line interface (CLI) to manage Kong in a declarative way. This allows organizations to manage their configuration in Git repositories, manage version control and leverage GitOps to automate the application of the configuration.
From a business perspective, establishing a CI/CD process accelerates innovation, increases quality and provides better customer satisfaction.
In this blog post, I will navigate through how to set up GitHub Action with decK to start GitOps for Kong. By the end of this post, we will be able to open a pull request (PR) in GitHub that will:
- Validate the configuration being applied via `deck validate` and list how the configuration will change via `deck diff`
- Apply the new configuration via `deck sync` when you merge the pull request
To accomplish these, we will set up two workflows - one on a pull request and the other on merge to master. The PR action will do `deck diff` and the merge to master will do `deck sync`, respectively.
Prerequisites
- Access to GitHub or GitHub Enterprise Server
- Access to GitHub Actions as part of your GitHub subscriptions
- Kong instance is already set up (this post assumes you're using Kong Enterprise, but the Kong Gateway open source version should work as well)
- Kong instance can be reached from GitHub Actions (if your instance is behind a corporate firewall, GitHub's self-hosted runner would be a good option)
- decK is installed
Preparation
Let's start by creating directories to store the configurations:
$ mkdir -p my-first-deck-in-action/kong
$ cd my-first-deck-in-action/kong
In my case, I have an existing Kong environment; therefore, I will first export my existing configuration with deck dump.
$ deck dump --kong-addr http://example.com:8001 --headers Kong-Admin-Token:*** --all-workspaces
Please make sure the `–kong-addr` option points to your Kong Admin API base url, and add the `–headers` option to embed your admin token if your Kong is configured with `rbac: on`. For Kong Enterprise users, the `–all-workspaces` will export all configurations from each workspace.
This command will return no output when successfully executed:
$ ls -al
total 24
drwxr-xr-x 5 ikedatakafumi staff 160 Mar 21 22:33 .
drwxr-xr-x 3 ikedatakafumi staff 96 Mar 21 22:33 ..
-rw------- 1 ikedatakafumi staff 1597 Mar 21 22:33 IT.yaml
-rw------- 1 ikedatakafumi staff 1598 Mar 21 22:33 LOB.yaml
-rw------- 1 ikedatakafumi staff 43 Mar 21 22:33 default.yaml
NOTE: Please note that your Kong configuration may contain sensitive information. Please take proper precautions to protect your declarative config.
In my case, Kong has three workspaces, which are IT, LOB and default, as you can see below.
Now, you have declarative configuration files on the file system. Let's store those in a Git repository.
$ cd ..
$ git init
Initialized empty Git repository in /Users/ikedatakafumi/Documents/workspace/my-first-deck-in-action/.git/
$ git add .
$ git commit -m "First commit"
[master (root-commit) 565c2cb] First commit
3 files changed, 158 insertions(+)
create mode 100644 kong/IT.yaml
create mode 100644 kong/LOB.yaml
create mode 100644 kong/default.yaml
You have now successfully stored the files into a local gGit repository. Let's push them to GitHub by first creating a repo in GitHub, Choose either public or private for this post.
When you are creating a repo in GitHub, please make sure not to initialize README for the following step work.
After the repo is created, you will see the instructions below:
With the Github repository created, we can now add and push to it:
git remote add origin git@github.com:ikeike443/my-first-deck-in-action.git branch -M main
$ git push -u origin main
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 1010 bytes | 1010.00 KiB/s, done.
Total 6 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To github.com:ikeike443/my-first-deck-in-action.git
* [new branch] main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
Now, you have successfully set up your Git repository for Kong configuration. You can see the yaml file(s) in GitHub like below:
Set Up GitHub Actions
Let's set up a GitHub Action to automatically deploy configurations to Kong.
To accomplish this most easily, we need to create several files on the same Git repository, as demonstrated below:
First, create action.yaml, which states the basic definition of the action, including the base image it relies on and the parameters to run:
$ pwd # make sure you're at the root of the repository
/Users/ikedatakafumi/Documents/workspace/my-first-deck-in-action
$ cat <<'EOF' | tee action.yaml
name: 'decK action'
description: 'Declarative Configuration management for Kong'
inputs:
command:
description: 'A decK command you want to execute'
required: true
default: 'ping'
kong_workspaces:
description: 'Kong workspaces where yaml files are located'
required: true
default: 'kong'
options:
description: 'Option parameters for a decK command'
required: false
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.command }}
- ${{ inputs.kong_workspaces }}
- ${{ inputs.options }}
EOF
We need to create a Dockerfile as defined in the yaml file. There's a Docker image for decK we can use as a base image.
$ cat <<'EOF' | tee Dockerfile
FROM kong/deck
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]
EOF
Next, we need to create an entrypoint.sh file as referenced in the Dockerfile. This script will execute the decK commands against the files under the directory specified in action.yaml. The script also makes sure only several sub-commands are going to run, such as ping, validate, diff and sync.
$ cat <<'EOF' | tee entrypoint.sh
#!/bin/sh -l
set -e -o pipefail
main (){
cmd=$1
dir=$2
ops=$3
if [ ! -e ${dir} ]; then
echo "${dir}: No such file or directory exists";
exit 1;
fi
for file in $(ls ${dir}); do
echo "Executing: deck $cmd $ops -s $dir/$file"
deck $cmd $ops -s $dir/$file
done
}
case $1 in
"ping") deck $1 $3;;
"validate"|"diff"|"sync") main $1 $2 "$3" ;;
* ) echo "deck $1 is not supported." && exit 1 ;;
esac
EOF
Make sure to give this file permission to execute:
$ chmod +x entrypoint.sh
Now, we have successfully set up the action. Let's create a workflow file that runs the action.
Workflow files should be located under `.github/workflow/` directory.
Let's create the `.github/workflow/` directory as shown below:
$ pwd # make sure you're at the root of the repository
/Users/ikedatakafumi/Documents/workspace/my-first-deck-in-action
$ mkdir -p .github/workflows
We will set up two workflows - one on a pull request and the other on a merge event. The action on the pull request will validate that the configuration being deployed is valid and shows the difference between the current Kong configuration and the configuration being applied. This allows the developer and/or PR reviewers to validate that the configuration is correct. The action on the merge will apply the new configuration to Kong.
Set Up Workflow on a Pull Request
First, we will set up the workflow on a pull request event that validates the configuration. Let's create `.github/workflows/CI.yaml` with your favorite editor, as shown below.
NOTE: I'm using a Kong Enterprise instance with RBAC enabled. If your instance has RBAC disabled, remove the `–headers ${{ secrets.KONG_HEADERS }}”` from the options section of each step in the workflow.
name: CI
on:
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
name: "checkout"
- name: decK ping
id: decK_ping
uses: ./
with:
command: "ping"
options: "--kong-addr ${{ secrets.KONG_ADDR }} --headers ${{ secrets.KONG_HEADERS }}"
- name: decK validate
id: decK_validate
uses: ./
with:
command: "validate"
options: "--kong-addr ${{ secrets.KONG_ADDR }} --headers ${{ secrets.KONG_HEADERS }}"
kong_workspaces: "kong"
- name: decK diff
id: decK_diff
uses: ./
with:
command: "diff"
options: "--kong-addr ${{ secrets.KONG_ADDR }} --headers ${{ secrets.KONG_HEADERS }}"
kong_workspaces: "kong"
The workflow will execute four steps sequentially:
- Check out the source codes on the step "checkout"
- Execute the `deck ping` command to confirm decK can connect to Kong
- Execute `deck validate` to confirm the configuration file is valid
- Execute `deck diff` to show the difference between the configuration file and the current configuration of Kong
Notice in the "options" section there are additional variables like `${{ secrets.KONG_ADDR }}`. These variables refer to secrets stored in GitHub, which allow the actions to reference data securely. See more detail about this functionality here: https://help.github.com/en/actions/configuring-and-managing-workflows/using-variables-and-secrets-in-a-workflow.
Next, let's push all the files we created to GitHub now.
$ git add .
$ git commit -m "My first actions"
[main 6a2cad0] My first actions
3 files changed, 50 insertions(+)
create mode 100644 Dockerfile
create mode 100644 action.yaml
create mode 100644 entrypoint.sh
$ git push --set-upstream origin main
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 953 bytes | 476.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)
To github.com:ikeike443/my-first-deck-in-action.git
565c2cb..6a2cad0 main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
After successfully pushing the latest changes to GitHub, the repository should look like this:
Let's now set the secrets that the action will use by going to the GitHub UI, Settings and Secrets section on the side panel.
Add a new secret for KONG_ADDR, and if RBAC is turned on in your Kong installation, add another secret for KONG_HEADERS, which contains "Kong-Admin-Token:***".
We're all set! Let's confirm the action on a pull request works.
Open a Pull Request to Trigger the Workflow
Let's open a pull request by modifying the Kong configuration file(s). In my case, I'm going to modify kong/LOB.yaml. I've changed the retry value 130 to 13 on the "retries" section under "httpbin_anything" services object.
Next, I'll create a new branch, commit this change to the branch and push it to GitHub. Then I'll open a new pull request in the GitHub UI. If you are not familiar with how to open a pull request, please see: https://guides.github.com/activities/hello-world/.
After successfully opening a pull request, the GitHub Action should start running.
We can see the result of the action in the "Checks" tab in the pull request as shown below.
Reviewing the results of the Action, we should see the results of the decK commands. In particular, deck diff shows how the Kong configuration will change when the changes are merged.
Set Up Workflow on a Merge Event
Let's set up another workflow to apply the new Kong configuration on a merge event.
To do this, please create another yaml file under `.github/workflows` directory. Let's call it "sync.yaml" like below:
NOTE: I'm using a Kong Enterprise instance with RBAC enabled. If your instance has RBAC disabled, remove the `–headers ${{ secrets.KONG_HEADERS }}”` from the options section of each step in the workflow.
name: Sync
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
name: "checkout"
- name: decK ping
id: decK_ping
uses: ./
with:
command: "ping"
options: "--kong-addr ${{ secrets.KONG_ADDR }} --headers ${{ secrets.KONG_HEADERS }}"
- name: decK validate
id: decK_validate
uses: ./
with:
command: "validate"
options: "--kong-addr ${{ secrets.KONG_ADDR }} --headers ${{ secrets.KONG_HEADERS }}"
kong_workspaces: "kong"
- name: decK sync
id: decK_sync
uses: ./
with:
command: "sync"
options: "--kong-addr ${{ secrets.KONG_ADDR }} --headers ${{ secrets.KONG_HEADERS }}"
kong_workspaces: "kong"
With this action, when changes are pushed to the master branch or a pull request is merged to master, the `deck sync` command will run to apply the configuration to Kong.
After the workflow has successfully finished, we can verify the new configuration was successfully applied. Let's validate using Kong Manager.
Congratulations! We have successfully set up a CI/CD pipeline to manage the Kong configuration declaratively using GitHub Actions!
For your convenience, I've created a reusable GitHub Action for decK, which you can fork and modify for your environment: https://github.com/ikeike443/decK-action.
Conclusion
In this post, we configured how to set up GitHub Actions to configure Kong declaratively with GitOps using decK. If you have any questions, please feel free to contact me on GitHub.
Happy hacking!