The CI/CD and DevOps Blog

Kubernetes Tutorial: how to pull a private docker image in a pod

Docker images that comprise a production application are often deployed to private repositories in Docker registries. Kubernetes provides a feature called imagePullSecrets that allows pods to pull private docker images. In this blog, we demonstrate how you can easily hookup imagePullSecrets to your pod using Shippable.

 

Creating an imagePullSecrets secret

imagePullSecrets is a type of a Kubernete Secret whose sole purpose is to pull private images from a Docker registry. It allows you to specify the Url of the docker registry, credentials for logging in and the image name of your private docker image.

There are two ways an imagePullSecrets can be created.

1. kubectl create secret docker-registry command. We use this approach in our blog.

ambarishs-MacBook-Pro:gke ambarish$ kubectl create secret docker-registry private-registry-key --docker-username="devopsrecipes" --docker-password="xxxxxx" --docker-email="[email protected]" --docker-server="https://index.docker.io/v1/"
secret "private-registry-key" created

 

2. Creating the secret via a yml.

In this approach, a config.json file is created for the private registry. Its contents are then base64 encoded and specified in the .dockerconfigjson property.

apiVersion: v1
kind: Secret
metadata:
  name: private-registry-key
  namespace: default
data:
  .dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
type: kubernetes.io/dockerconfigjson

 

Kubernetes Tutorial: Using Secrets In Your Application

Applications deployed to a Kubernetes cluster often need access to sensitive information such as credentials to access a database and authentication tokens to make authenticated API calls to services. Kubernetes allows you to specify such sensitive information cleanly in an object called a Secret. This avoids putting sensitive data in a Pod defintion or a docker image. In this blog, we demonstrate how you can easily hookup Kubernetes Secrets to your pod using Shippable.

 

Creating a Kubernetes Secret

Secrets are defined in a yml file in a Secret object. A Secret object can specifiy multiple secrets in name-value pairs. Each secret has to be base64 encoded before specifying it in the yml.

Let's define an API token as a secret for a fake token xxx-xxx-xxx.

1. Base 64 encode the token.

ambarishs-MacBook-Pro:sources ambarish$ echo -n "xxx-xxx-xxx" | base64
eHh4LXh4eC14eHg=

2. Create the secrets yml called create-secret.yml.

apiVersion: v1
kind: Secret
metadata:
  name: auth-token-secret
type: Opaque
data:
  AUTH_TOKEN_VALUE: eHh4LXh4eC14eHg=

3. Create the secret in the kubernetes cluster using kubectl.

$ kubectl create -f secrets.yml
secret "auth-token" created

Kubernetes Tutorial: Attaching A Volume Mount To Your Application

Kubernetes allows you to package multiple containers into a pod. All containers in the pod run on the same Nodeshare the IP address and port space, and can find each other via localhost. To share data between pods, Kubernetes has an abstraction called Volumes. In this blog, we demonstrate how you can  easily hookup Kubernetes Volumnes to your pod and define the containers in the pod using Shippable.

 

Kuberetes Volumes

A Volume is a directory with data that is accessible to all containers running in a pod and gets mounted into each containers filesystem. Its lifetime is identical to the lifetime of the pod. Decoupling the volume lifetime from the container lifetime allows the volume to persist across container crashes and restarts. Volumes further can be backed by host's filesystem, by persistent block storage volumes such as AWS EBS or a distributed file system. The complete list of the different types of volumes that Kubernetes supports can be found here.

Shippable supports mounting all the types of volumes that Kubernetes supports via the dockerOptions resource. However, the specific volume type that we demonstrate in this blog is a gitRepo volume. A gitRepo volume mounts a directory into each containers filesystem and clones a git repository into it. 

Kubernetes Tutorial: Deploying a load-balanced Docker application

Kubernetes is a Production grade container orchestration platform with automated scaling and management of containerized applications. It is also open source, so you can install Kubernetes on any cloud like AWS, Digital Ocean, Google Cloud Platform, or even just on your own machines on premises. Kubernetes was started at Google and is also offered as a hosted Container Service called GKE. With Shippable, you can easily hook up your automated DevOps pipeline from source control to deploy to your Kubernetes pods and accelerate innovation.

In this blog, we demonstrate how to deploy a load balanced, multi-container application to multiple Kubernetes environments on GKE. The deployment occurs in multiple stages in a Shippable defined workflow.

 

Kubernetes Deployment spec

The pods and services (load balancer) for the application are created using a deployment spec. Instead of creating and maintaining a deployment spec per environment which is a common practice, we create a single deployment spec template. This template has placeholders for the image and service/pod labels. When we deploy the application to a specific environment, we use powerful yet simple Shippable platform functions and resources to  replace these placeholders at run time when the deployment actually happens.

The deployment spec template (located here in our public repository) defines the label selectors placeholders in the .spec.selector section and the labels for the pods in the .spec.template.metadata.labels section. Labels are defined for both the front end voting application (FE_LABEL) as well as the Redis service (BE_LABEL) which the front ends makes API calls on via another load balancer.   

CI/CD For Microservices Using Monorepos

We wrote a very popular blog a little over a year ago, detailing the reasone behind our choice of organizing our microservices codebase in a single repository called a mono repo. 

Since then, we've often been asked - how do you set up a CI/CD pipeline for a mono repo? When a code change to the repository triggers CI, how does your CI know which microservice changed so that it can rebuild and test just that service?

In this blog, we will demonstrate how the Shippable platform makes it simple to independently build, test and deploy microservices from a mono repo. For simplicity,  we will use a monorepo sample (that you can fork) that consists of just two microservices, and create a CI/CD pipeline with Amazon ECR and ECS. 

Scenario

  • Our Node.js application has two microservices: a front-end microservice www that makes API calls to a backend API microservice called api. The source code for both microservices is in separate folders in a mono repo.

  • Each microservice is packaged as a Docker image during the build process and has its own independent unit tests.

  • Each Docker image is pushed to its own Amazon ECR repository. Both images get deployed to a common Amazon ECS cluster.   

  • Both these microservice share some common code that is maintained in a separate folder in the mono repo.

  • A commit to a microservice builds, tests and deploys that specific microservice.

  • A commit to the common code builds, tests and deploys both microservices.