Shipping images with a registry

1. Introduction

  • Initially, our app was running on a single node

  • We could build and run in the same place

  • Therefore, we did not need to ship anything

  • Now that we want to run on a cluster, things are different

  • The easiest way to ship container images is to use a registry

How Docker registries work (a reminder)

  • What happens when we execute docker run alpine ?

  • If the Engine needs to pull the alpine image, it expands it into library/alpine

  • library/alpine is expanded into index.docker.io/library/alpine

  • The Engine communicates with index.docker.io to retrieve library/alpine:latest

  • To use something else than index.docker.io, we specify it in the image name

  • Examples:

    docker pull gcr.io/google-containers/alpine-with-bash:1.0
    
    docker build -t registry.mycompany.io:5000/myimage:awesome .
    docker push registry.mycompany.io:5000/myimage:awesome
    

Running DockerCoins on Kubernetes

  • Create one deployment for each component

    (hasher, redis, rng, webui, worker)

  • Expose deployments that need to accept connections

    (hasher, redis, rng, webui)

  • For redis, we can use the official redis image

  • For the 4 others, we need to build images and push them to some registry

Building and shipping images

  • There are many options!

  • Manually:

    • build locally (with docker build or otherwise)

    • push to the registry

  • Automatically:

    • build and test locally

    • when ready, commit and push a code repository

    • the code repository notifies an automated build system

    • that system gets the code, builds it, pushes the image to the registry

Which registry do we want to use?

  • There are SAAS products like Docker Hub, Quay ...

  • Each major cloud provider has an option as well

    (ACR on Azure, ECR on AWS, GCR on Google Cloud...)

  • There are also commercial products to run our own registry

    (Docker EE, Quay...)

  • And open source options, too!

  • When picking a registry, pay attention to its build system

    (when it has one)

2. Self-hosting our registry

Note: this section shows how to run the Docker open source registry and use it to ship images on our cluster. While this method works fine, we recommend that you consider using one of the hosted, free automated build services instead. It will be much easier!

If you need to run a registry on premises, this section gives you a starting point, but you will need to make a lot of changes so that the registry is secured, highly available, and so that your build pipeline is automated.

Using the open source registry

  • We need to run a registry container

  • It will store images and layers to the local filesystem
    (but you can add a config file to use S3, Swift, etc.)

  • Docker requires TLS when communicating with the registry

    • unless for registries on 127.0.0.0/8 (i.e. localhost)

    • or with the Engine flag --insecure-registry

  • Our strategy: publish the registry container on a NodePort,
    so that it's available through 127.0.0.1:xxxxx on each node

Deploying a self-hosted registry

  • We will deploy a registry container, and expose it with a NodePort

Exercise

  • Create the registry service:

    kubectl create deployment registry --image=registry
    
  • Expose it on a NodePort:

    kubectl expose deploy/registry --port=5000 --type=NodePort
    

Connecting to our registry

  • We need to find out which port has been allocated

Exercise

  • View the service details:

    kubectl describe svc/registry
    
  • Get the port number programmatically:

    NODEPORT=$(kubectl get svc/registry -o json | jq .spec.ports[0].nodePort)
    REGISTRY=127.0.0.1:$NODEPORT
    

Testing our registry

  • A convenient Docker registry API route to remember is /v2/_catalog

Exercise

  • View the repositories currently held in our registry:

    curl $REGISTRY/v2/_catalog
    

We should see:

{"repositories":[]}

Testing our local registry

  • We can retag a small image, and push it to the registry

Exercise

  • Make sure we have the busybox image, and retag it:

    docker pull busybox
    docker tag busybox $REGISTRY/busybox
    
  • Push it:

    docker push $REGISTRY/busybox
    

Checking again what's on our local registry

  • Let's use the same endpoint as before

Exercise

  • Ensure that our busybox image is now in the local registry:
    curl $REGISTRY/v2/_catalog
    

The curl command should now output:

{"repositories":["busybox"]}

Building and pushing our images

  • We are going to use a convenient feature of Docker Compose

Exercise

  • Go to the stacks directory:

    cd ~/container.training/stacks
    
  • Build and push the images:

    export REGISTRY
    export TAG=v0.1
    docker-compose -f dockercoins.yml build
    docker-compose -f dockercoins.yml push
    

Let's have a look at the dockercoins.yml file while this is building and pushing.

version: "3"

services:
  rng:
    build: dockercoins/rng
    image: ${REGISTRY-127.0.0.1:5000}/rng:${TAG-latest}
    deploy:
      mode: global
  ...
  redis:
    image: redis
  ...
  worker:
    build: dockercoins/worker
    image: ${REGISTRY-127.0.0.1:5000}/worker:${TAG-latest}
    ...
    deploy:
      replicas: 10

Just in case you were wondering ... Docker "services" are not Kubernetes "services".

Avoiding the latest tag

Make sure that you've set the TAG variable properly!

  • If you don't, the tag will default to latest

  • The problem with latest: nobody knows what it points to!

    • the latest commit in the repo?

    • the latest commit in some branch? (Which one?)

    • the latest tag?

    • some random version pushed by a random team member?

  • If you keep pushing the latest tag, how do you roll back?

  • Image tags should be meaningful, i.e. correspond to code branches, tags, or hashes

Checking the content of the registry

  • All our images should now be in the registry

Exercise

  • Re-run the same curl command as earlier:

    curl $REGISTRY/v2/_catalog
    

In these slides, all the commands to deploy DockerCoins will use a $REGISTRY environment variable, so that we can quickly switch from the self-hosted registry to pre-built images hosted on the Docker Hub. So make sure that this $REGISTRY variable is set correctly when running the exercises!

3. Using images from the Docker Hub

  • For everyone's convenience, we took care of building DockerCoins images

  • We pushed these images to the DockerHub, under the dockercoins user

  • These images are tagged with a version number, v0.1

  • The full image names are therefore:

    • dockercoins/hasher:v0.1

    • dockercoins/rng:v0.1

    • dockercoins/webui:v0.1

    • dockercoins/worker:v0.1

Setting $REGISTRY and $TAG

  • In the upcoming exercises and labs, we use a couple of environment variables:

    • $REGISTRY as a prefix to all image names

    • $TAG as the image version tag

  • For example, the worker image is $REGISTRY/worker:$TAG

  • If you copy-paste the commands in these exercises:

    make sure that you set $REGISTRY and $TAG first!

  • For example:

    export REGISTRY=dockercoins TAG=v0.1
    

    (this will expand $REGISTRY/worker:$TAG to dockercoins/worker:v0.1)