Deploying to Kubernetes

Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications

There are three key points to understand in Kubernetes:

  • Cluster — a set of VMs (called nodes) that will be used to run your containers
  • Deployment — an instance of your app. If your app does not need to expose any endpoints to the outside world then this will be all you need (e.g. your app only communicates with other containers in your cluster, only fetches data from another external API, or it connects to an amqp exchange and processes messages). This can also be replicated multiple times to scale your app.
  • Pod — its best to imagine this as a single VM, with a running instance of your container or group of containers that benefit from being on the same machine.
  • Service — you create this to make your app accessible from the public network (because by default it can’t be accessed by anything that isn’t running inside the same container). You should add a load balancer if you have multiple replicas of your deployment so that requests can be shared fairly between your app’s instances.

The first thing you need to do is define a kubernetes config file:

kubernetes-deploy.yml

apiVersion: v1
kind: Service
metadata:
name: <codename>
labels:
# Labels are used when determining which deployments this service will forward traffic to
project: <project-name>
name: <service-name>
env: <environment>
spec:
# Type LoadBalancer will expose an external IP.
type: LoadBalancer
selector:
# The selector to match the labels
project: <project-name>
name: <service-name>
env: <environment>
ports:
- name: "http"
# The 'port' refers to the EXTERNAL port (i.e. the public facing port) number.
port: <port-external>
# The 'target' port is the port on the container to which the service needs to forward the traffic.
targetPort: <port-internal>
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: <codename>
spec:
replicas: <replicas>
template:
metadata:
# Labels which the Service uses when selecting services to forward traffic to.
labels:
project: <project-name>
name: <service-name>
env: <environment>
spec:
containers:
- name: <service-name>
image: gcr.io/<gcr-project>/<image-name>:<project-version>
imagePullPolicy: Always # needed this so that my development images are always repulled even though they have the same tag
ports:
- name: 'http'
# The port your application is listening on.
containerPort: <port-internal>
env:
- name: NODE_ENV
value: <NODE_ENV>
- name: AMQP_HOST
value: <AMQP_HOST>

I use a bash script to replace (sed) all the variables into the file before using kubectl (kubernetes’ commandline tool) to apply the configuration to my cluster:

create-deploy-file.sh

#!/bin/shcat kubernetes-deploy.yml \
| sed "s^<project-name>^$PROJECT^g" \
| sed "s^<service-name>^$SERVICE^g" \
| sed "s^<image-name>^$WERCKER_GIT_REPOSITORY^g" \
| sed "s^<codename>^$SERVICE-$ENVIRONMENT^g" \
| sed "s^<environment>^$ENVIRONMENT^g" \
| sed "s^<replicas>^3^g" \
| sed "s^<project-version>^$PACKAGE_VERSION^g" \
| sed "s^<port-internal>^8080^g" \
| sed "s^<port-external>^80^g" \
| sed "s^<NODE_ENV>^$NODE_ENV^g" \
| sed "s^<AMQP_HOST>^$AMQP_HOST^g" \
> deploy-config.yml
  • You can add more lines to replace more variables as you see fit, or hardcode any variables you don’t forsee changing in you config.
  • I used ‘^’ as the delimiter because ‘/’ was causing problems with urls.

Once we have these two files, we can finally add a wercker pipeline for deployment to kubernetes.

deploy:
steps:
- script:
name: export package version
code: |
[ "$WERCKER_GIT_BRANCH" = "master" ] \
&& export PACKAGE_VERSION=$(node -p -e "require('./package.json').version") \
|| export PACKAGE_VERSION=development
- script:
name: create the deployment file
code: ./create-deploy-file.sh
- kubectl:
server: $KUBERNETES_CLUSTER_SERVER_URL
username: $KUBERNETES_USERNAME
password: $KUBERNETES_PASSWORD
insecure-skip-tls-verify: true
command: apply -f deploy-config.yml

This will apply your config to your cluster and deploy your application with the image tagged with your PACKAGE_VERSION env variable and injects other environment variables you have configured in your wercker setup.

The final step is to add the pipeline to your workflows in wercker’s online UI and you’re done! You now have automated deployment set up in your project.

Before we set this up at my work deployment would take a couple of hours and would require a lot of manual configuration and setup, also introducing the risk of making mistakes. Now, I can kick of a deployment from my phone with the click of a button.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade