Recently GitHub released a new feature called Actions. To me, it looks like the best implementation I can think of for serverless. I used AWS Lambda and API Gateway for some basic API, and I wrote a prototype of an application capable of running functions using containers called gourmet I don’t buy the fact that it will make my code easy to manage. At least not to write API or web applications.

I used the #GitHubActions to verify and deploy code to a #kubernetes cluster https://t.co/nfkjmYKPKs I am impressed about how wonderful this feature is designed and implemented! @Github you 🤘! — :w !sudo tee % (@GianArb) January 22, 2019

That’s why I like what GitHub did because they used serverless for what I think it is designed for, extensibility.

GitHub Actions just like Lambda functions on AWS are a powerful and managed way to extend their product straightforwardly.

With AWS Lambda you can hook your code to almost whatever event happens: EC2 creations, termination, route53 DNS record change and a lot more. You don’t need to run a server, you load your code, and it just works.

Jess Frazelle wrote a blog post about “The Life of a GitHub Action, and I decided to try something I had my mind since a couple of weeks but it required a CI server, and it was already too much for me.

Time to time I like the idea to have a kubernetes cluster that I can use for the testing purpose, so I created a private repository that it is not ready to be open source because it is a mess with secrets inside and so on.

In any case, to give you an idea, this is the project’s folder:

├── .github │ ├── actions │ │ ├── deploy │ │ │ ├── deploy │ │ │ └── Dockerfile │ │ └── dryrun │ │ ├── Dockerfile │ │ └── dryrun │ └── main.workflow └── kubernetes ├── digitalocean.yaml ├── external-dns.yaml ├── micro.yaml ├── namespaces.yaml ├── nginx.yaml └── openvpn.yaml

The kubernetes directory contains all the things I would like to install in my cluster. For every new push on this repository, I would like to check if it can be applied to the kubernetes cluster with the command kubectl apply -f ./kubernetes --dryrun and when the PR is merged the changes should get applied.

So I created my workflow in .github/main.workflow : ( I left some comment to make it understandable)

## Workflow defines what we want to call a set of actions. ## For every new push check if the changes can be applied to kubernetes ## using the action called: kubectl dryrun workflow "after a push check if they apply to kubernetes" { on = "push" resolves = ["kubectl dryrun"] } ## When a PR is merged trigger the action: kubectl deploy. To apply the new code to master. workflow "on merge to master deploy on kubernetes" { on = "pull_request" resolves = ["kubectl deploy"] } ## This is the action that checks if the push can be applied to kubernetes action "kubectl dryrun" { uses = "./.github/actions/dryrun" secrets = ["KUBECONFIG"] } ## This is the action that applies the change to kubernetes action "kubectl deploy" { uses = "./.github/actions/deploy" secrets = ["KUBECONFIG"] }

The secrets are an array of environment variables that you can use to set values from the outside. If your account has GitHub Action enabled there is a new Tag inside the Settings in every repository called “Secrets.”

You can set key-value pairs usable as you see in my workflow. For this example, I set the KUBECONFIG as the base64 of a kubeconfig file that allows the GitHub Action to authorize itself to my Kubernetes cluster.

Both actions are similar the first one is in the directory .github/actions/dryrun

├── .github ├── actions └── dryrun ├── Dockerfile └── dryrun

It contains a Dockerfile

FROM alpine:latest ## The action name displayed by GitHub LABEL "com.github.actions.name"="kubectl dryrun" ## The description for the action LABEL "com.github.actions.description"="Check the kubernetes change to apply." ## https://developer.github.com/actions/creating-github-actions/creating-a-docker-container/#supported-feather-icons LABEL "com.github.actions.icon"="check" ## The color of the action icon LABEL "com.github.actions.color"="blue" RUN apk add --no-cache \ bash \ ca-certificates \ curl \ git \ jq RUN curl -L -o /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubectl && \ chmod +x /usr/bin/kubectl && \ kubectl version --client COPY dryrun /usr/bin/dryrun CMD ["dryrun"]

As you can see to describe an action, you need just a Dockerfile, and it works the same as in docker. The CMD dryrun is the bash script I copied here:

#!/bin/bash main (){ echo ">>>> Action started" # Decode the secret passed by the action and paste the config in a file. echo $KUBECONFIG | base64 -d > ./kubeconfig.yaml echo ">>>> kubeconfig created" # Check if the kubernetes directory has change diff = $( git diff --exit-code HEAD~1 HEAD ./kubernetes ) if [ $? -eq 1 ] ; then echo ">>>> Detected a change inside the kubernetes directory" # Apply the changes with --dryrun just to validate them kubectl apply --kubeconfig ./kubeconfig.yaml --dry-run -f ./kubernetes else echo ">>>> No changed detected inside the ./kubernetes folder. Nothing to do." fi } main " $@ "

The second action is almost the same as this one, the Dockerfile is THE same, so I am not posting it here, but the CMD looks like this:

#!/bin/bash main (){ # Decode the secret passed by the action and paste the config in a file. echo $KUBECONFIG | base64 -d > ./kubeconfig.yaml # Check if it is an event generated by the PR is a merge merged = $( jq --raw-output .pull_request.merged " $GITHUB_EVENT_PATH " ) # Retrieve the base branch for the PR because I would like to apply only PR merged to master baseRef = $( jq --raw-output .pull_request.base.ref " $GITHUB_EVENT_PATH " ) if [[ " $merged " == "true" ]] && [[ " $baseRef " == "master" ]] ; then echo ">>>> PR merged into master. Shipping to k8s!" kubectl apply --kubeconfig ./kubeconfig.yaml -f ./kubernetes else echo ">>>> Nothing to do here!" fi } main " $@ "

That’s everything, and I am thrilled!

There is nothing more to say other than “GitHub actions are amazing!”. They look well designed since day! The workflow file has a generator that even if I didn’t use it because I don’t like colors, it seems amazing. The secrets allow us to do integration with third-party services out of the box and you can use bash to do whatever you like! Let me know what you use them for on Twitter.