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=""
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
  name: private-registry-key
  namespace: default
  .dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==


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

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

apiVersion: v1
kind: Secret
  name: auth-token-secret
type: Opaque

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. 

Security Best Practices At Shippable

In light of a recent blog post about a competitor's security vulnerabilities, I wanted to be completely transparent about our security best practices to reassure our customers that they're in good hands.

From the start, we've been very aware of the fact that when customers click on the Authorize button to grant us access to their GitHub or Bitbucket repositories, they trust us with their Intellectual Property.  This is a tremendous step, especially since we're all aware of hackers attacking almost every major site and stealing personal information.

Our security measures fall under two pillars, Product and Process, both of which are explained below.

Configuring Multi-Stage CI

In this blog, we demonstrate how to use the Shippable platform to perform Multi-Stage CI on your repositories. The key benefit of Multi-Stage CI is to split a time-consuming CI process into smaller stages to detect issues in code quality / tests as early as possible and shorten the feedback loop on every checkin. This often entails refactoring or designing your application into smaller components and testing each component in isolation first before running more expensive integration tests of your component with other components in the system.

What is multi-stage CI?

In our multi-stage CI scenario, we split the CI of a Node.js app into several stages.

  • Stage 1: Stage 1 runs on every PR and lints the source code in the repository to find style errors. To learn more about the benifits of linting your javascript code, look at this article. The idea behind Stage 1 is to perform a quick code quality check on every PR and shorten the feedback loop for any errors in coding style and bugs found during static analysis. This allows developers to quickly find and fix issues in their PRs.
  • Stage 2: Stage 2 runs on successful completion of Stage 1. In Stage 2, we run a small subset of tests to quickly validate the PR.
  • Stage 3: Stage 3 runs on the merged commit to the repository. Here we run a broader set of core unit tests that take longer to run than Stage 2.