Docker is one of the more popular container platforms for developers and sysadmins to develop, deploy, and run applications with containers. The use of Linux containers to deploy applications is called containerization that has lot more advantages over traditional virtualization as containers are much more efficient, fast, and lightweight.

Docker features the Docker Engine, which is a runtime and allows you to build and run containers, and includes DockerHub, a service for storing and sharing images. Docker also offers its own native clustering tool that can be used to orchestrate and schedule containers on machine clusters.

Since we’re talking about Docker, it’s natural that we also talk about Kubernetes, a container orchestration system for Docker containers that is more extensive than Docker Swarm and is meant to coordinate clusters of nodes at scale in production in an efficient manner.

Kubernetes and Docker are essentially the same technology – they orchestrate containers and they both use containerd or runC to do so. But they are different projects with a differing view on how users get their job done – they also work very well together, and both facilitate the management and deployment of containers in a distributed architecture.

Most organizations store proprietary Docker images in private registries. While it is easy to deploy public Docker images to Kubernetes, there are some additional steps involved when you’re dealing with private images. Docker Cloud uses DockerHub as its native registry for storing both public and private repositories.

Learning objectives

This tutorial shows you how to configure a Kubernetes cluster to access public and private images from DockerHub.

In this tutorial, you’ll learn the following:

  • Push Docker images (Public & Private) to a DockerHub repository.
  • Create a Kubernetes cluster from the CLI.
  • Create a secret in the Kubernetes cluster to access private repositories.
  • Deploy and access images from the DockerHub Regisry in the IBM Cloud Kubernetes Service (IKS) environment.

Prerequisites

Before you begin, you’ll need

  • Free IBM Cloud Account. Don’t have an account? Register for a free trial account here.
  • IBM Cloud CLI. Get the download from here
  • Latest stable version of Docker. Sign up for a free account here
  • A Docker CLI. Get the download from here

Estimated time

Completing this tutorial should take about 30-40 minutes.

Steps

Upload Docker images to a DockerHub repository

You can use Docker images that are running on your local machine or download the example images used for this tutorial.

Here are the downloadable example images:

Create a public image repository on DockerHub

In this section, we’re going to start with current working directory of your application folder.

  cd <YOUR_WORK_DIRECTORY>

If you’re using the Python Example, change your working directory to get-started-python.

  cd get-started-python
  1. Log in to DockerHub.

  2. Click on Create Repository.

    Create repo

  3. Choose a name for your public image repository, that you will use in place of the field in following steps (e.g., get-started-python) and a description for your repository. Select Public to create public repository and click Create.

    DockerHub public repo

  4. Set the variable “docker_username” as your username. This allows you to copy and paste the commands directly from this tutorial:

    export docker_username="YOUR_DOCKER_USERNAME"
    
  5. Log in to DockerHub from the command line:

    docker login
    
  6. Build an image if you are using Python Example from this tutorial. (You can skip this step if you are using your local image and head to #8 Tag your image):

    docker build -t $docker_username/<YOUR_PUBLIC_REPO_IMAGE_NAME>:<TAG>
    

    For example:

    docker build -t $docker_username/get-started-python:v1.0.0
    

    In general, a good choice for a <TAG> is something that will help you understand what this container should be used with or what it represents. If this container contains the analysis for a paper, consider using that paper’s DOI or journal-issued serial number; if it’s meant for use with a particular version of a code or data version control repo, that’s a good choice, too – whatever will help you understand what this particular image is intended for.

    After executing the above command, you should see something like the following as output:

     .....
     Successfully built f7757ff0ebce
     Successfully tagged nidhinshah/get-started-python:v1.0.0
    
  7. Check the image ID by using following command.

    docker images
    

    You should see something like the following output:

    REPOSITORY                                  TAG                 IMAGE ID            CREATED             SIZE
    nidhinshah/get-started-python               v1.0.0              f7757ff0ebce        5 minutes ago       914MB
    
  8. Note : You don’t need to do this step if you built it, because we built it with the right tag name already. This step is only needed if you’re going to use some other image. So skip to the next step if applicable.

    Tag your image:

    docker tag <IMAGE ID> $docker_username/<YOUR_PUBLIC_REPO_IMAGE_NAME>:<TAG>
    

    For example:

    docker tag f7757ff0ebce $docker_username/get-started-python:v1.0.0
    
  9. Push your image to DockerHub.

    docker push $docker_username/<YOUR_PUBLIC_REPO_IMAGE_NAME>:<TAG>
    

    For example:

    docker push $docker_username/get-started-python:v1.0.0
    

    You should see something like the following as output:

    The push refers to repository [docker.io/nidhinshah/get-started-python]
    cb91dfda910f: Pushed
    2b28e48bbc09: Pushed
    ........
    ........
    v1.0.0: digest: sha256:b2ee76e81575bd74bad80d95f983af5701e2df4a8ed5288739c654aa6e591301 size: 2642
    
  10. Go to your DockerHub UI and you can see that your image is pushed to the public repository:

    PublicRepo image

  11. Run your image on Docker:

    docker run -it -d -p <PORT>:<PORT> $docker_username/<YOUR_PUBLIC_REPO_IMAGE_NAME>:<TAG>
    

    Note: You have to mention the Port number that you used to expose your application in your Dockerfile.

    For example:

    docker run -it -d -p 5000:5000 $docker_username/get-started-python:v1.0.0
    
  12. You can now access the application at http://localhost:5000.

    Python app output

Create a private image repository on DockerHub

Note: You can convert between private and public via the Settings page in DockerHub. You’re not stuck with the choice that you originally made when you first created the repo.

Private repositories allow you to have repositories that contain images that you want to keep private, either to your own account or within an organization or team.

To work with a private repository on DockerHub, you need to add one by using the Add Repository Procedure (Steps 1 – 3 from Create a public image repository on DockerHub). Then select Privat at Step 3.

DockerHub private repo

If you wish to use the Node Example from this tutorial, download it and cd into it, else cd into your work directory:

  cd <YOUR_WORK_DIRECTORY>`

For our Node example:

  cd get-started-node

Follow Steps 4-12 from Create a public image repository on DockerHub to push this private image to your DockerHub account.

You will see the following when accessing the Node Example.

Node app output

Node app output 2

Access DockerHub repositories from the IBM Cloud Kubernetes Service

We have created both public and private images and pushed them to our DockerHub account in previous steps. To access these repositories from IBM Cloud, we’ll configure the IBM Cloud Kubernetes Cluster.

Configure IBM Cloud Kubernetes cluster

  1. Log into your IBM Cloud account:

    ibmcloud login
    

    If you have a federated ID, use following:

    ibmcloud login --sso
    
  2. Install the Container Registry plug-in:

    ibmcloud plugin install container-registry -r "IBM Cloud"
    
  3. Install the Container Service plug-in:

    ibmcloud plugin install IBM-Containers -r "IBM Cloud"
    
  4. Install kubectl (follow directions here).

  5. Create the cluster:

    ibmcloud cs cluster-create --name <YOUR_CLUSTER_NAME>
    

    Where you see , give your cluster a unique name.

  6. Configure Kubernetes cluster:

    ibmcloud cs cluster-config <YOUR_CLUSTER_NAME>
    
  7. Set the KUBECONFIG environment variable. Copy the output from the previous command and paste it in your terminal.

    The command output should look similar to the following:

    export KUBECONFIG=/Users/$USER/.bluemix/plugins/container-service/clusters/cluster-demo/kube-config-hou02-  <YOUR_CLUSTER_NAME>.yml
    
  8. Verify that you can connect to your cluster by listing your worker nodes:

    kubectl get nodes
    

    You should see STATUS = Ready:

    NAME STATUS AGE VERSION 10.44.103.91 Ready 1d v1.10.8+IKS

Deploy the application from the public DockerHub repository

This is an easy approach and no additional setup is needed for your cluster.

  1. Make sure you are logged into your Docker account:

    docker login
    
  2. Run the following command to deploy your application to IBM Cloud Kubernetes Service (IKS) Cluster:

    kubectl run <YOUR_DEPLOYMENT_NAME> --image=docker.io/$docker_username/<YOUR_PUBLIC_REPO_IMAGE_NAME>:<TAG>
    

    Where you see <YOUR_DEPLOYMENT_NAME>, give your deployment a unique name. Where you see <YOUR_PUBLIC_REPO_IMAGE_NAME>, give your DockerHub Public Image Repository a unique name.

    For example:

    kubectl run get-started-python --image=docker.io/$docker_username/get-started-python:v1.0.0
    

    You will see an output with the following message:

    deployment "get-started-python" created
    
  3. To check your application pod, use:

    kubectl get pods
    

    You will see “Running” under your Pod STATUS for your deployed Application:

    NAME                                  READY     STATUS    RESTARTS   AGE
    get-started-python-6b7b786d7-47htj    1/1       Running   0          30s
    
  4. Expose the app to the web by setting the port.

    kubectl expose deployment/<YOUR_DEPLOYMENT_NAME> --type=NodePort --name=<YOUR_SERVICE_NAME> --port=<PORT>
    

    Where you see <YOUR_DEPLOYMENT_NAME>, give a name to your deployment. Where you see <YOUR_SERVICE_NAME>, give your service a unique name. Where you see <PORT>, the port should be the same as exposed in your Dockerfile.

    For example:

    kubectl expose deployment/get-started-python --type=NodePort --name=get-started-python --port=5000
    

    You will see an output with the following message:

    service "get-started-python" exposed
    

Deploy the application from your private DockerHub

You can connect any existing private registry to your IKS cluster by creating an imagePullSecret. The secret is used to securely save your registry URL and credentials in a Kubernetes secret.

  1. Create the Secret.

    kubectl create secret docker-registry <SECRET-NAME> --docker-server=<YOUR-REGISTRY-SERVER> --docker-username=   <YOUR_DOCKER_USERNAME> --docker-password=<YOUR_DOCKER_PASSWORD> --docker-email=<YOUR_DOCKER_EMAIL>
    

    Where you see <SECRET-NAME>, give a name that you want to use for your imagePullSecret. Where you see <YOUR-REGISTRY-SERVER>, input the URL to the registry where your private images are stored (https://index.docker.io/v1/ for DockerHub). Where you see <YOUR_DOCKER_USERNAME>, use your Docker username to log in to your private registry. Where you see <YOUR_DOCKER_PASSWORD>, use your Docker password. Where you see <YOUR_DOCKER_EMAIL>, use your Docker email address.

    You have now successfully set your Docker credentials in the cluster as a Secret called <SECRET-NAME>.

  2. Log in to your Docker account:

    docker login
    
  3. Create the deployment.yaml file:

    vi deployment.yaml
    

    Paste the following code to the deployment.yaml file and save the changes. Replace the values according to your credentials or use deployment.yaml file if you are using the Node Example.

    apiVersion: v1
    kind: Service
    metadata:
     name: <YOUR_SERVICE_NAME>
     labels:
       app: <YOUR_PRIVATE_IMAGE_NAME>
    spec:
     type: NodePort
     ports:
     - port: 3000
       name: http
       nodePort: 30080
     selector:
       app: <YOUR_PRIVATE_IMAGE_NAME>
    
     apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
     name: <YOUR_DEPLOYMENT_NAME>
    spec:
     replicas: 1
     template:
       metadata:
         labels:
           app: <YOUR_PRIVATE_IMAGE_NAME>
       spec:
         containers:
         - name: <YOUR_IMAGE_CONTAINER_NAME>
           image: docker.io/$docker_username/<PRIVATE_IMAGE_REPOSITORY_NAME>:<TAG>  
           ports:
           - containerPort: 3000
         imagePullSecrets:
         - name: <SECRET-NAME>
    

    Where you see <YOUR_SERVICE_NAME>, give your service a unique name. Where you see <YOUR_PRIVATE_IMAGE_NAME>, use your DockerHub Private Image name. Where you see <YOUR_DEPLOYMENT_NAME>, give your deployment a unique name. Where you see <YOUR_IMAGE_CONTAINER_NAME>, give your image container a unique name. Where you see <SECRET-NAME>, use the secret that you created in previous step (step 1).

  4. Run the application on Kubernetes with a yaml file:

    kubectl create -f deployment.yaml
    

    The output will display the following message:

    service "get-started-node-service" created
    deployment "get-started-node-deployment" created
    
  5. To check your application pod, use:

    kubectl get pods
    

    You will see “Running” under your Pod STATUS for your deployed Application:

    NAME                                           READY     STATUS    RESTARTS   AGE
    get-started-node-deployment-85b96dd6cf-mt6pd   1/1       Running   0          10s
    

Access your applications

Note: To access your application, you will need the public IP address of your cluster and NodePort of the service.

  1. For clusters provisioned with IBM Cloud, use:

    ibmcloud cs workers <YOUR_CLUSTER_NAME>
    

    For example:

    ibmcloud cs workers cluster-demo
    

    You will see an output similar to the following:

    OK
    ID                                                 Public IP         Private IP     Machine Type   State    Status   Zone         Version
    kube-hou02-pafd0092d812024958b05e2e9f1a88c8d9-w1   173.193.106.234   10.44.103.91   free           normal   Ready    hou02    1.10.8_1528
    
  2. For details on a specific Kubernetes service, use:

    kubectl describe service <YOUR_SERVICE_NAME>
    

    You can use this command to get details of both private/public images that you deployed from DockerHub.

    For example:

    kubectl describe service get-started-node-service
    

    You will see an output similar to the following:

    Name: get-started-node-service
    Namespace: default
    Labels: app=get-started-node
    Annotations: <none>
    Selector: app=get-started-node
    Type: NodePort
    IP: 172.21.131.88
    Port: http 3000/TCP
    NodePort: http 30090/TCP
    Endpoints: 172.30.41.26:3000
    Session Affinity: None
    Events: <none>
    
  3. You can now access the application at http://IP_ADDRESS:NODE_PORT.

Clean up

A cleanup will save you time and space, in case you decide you no longer want to use this deployment again.

  kubectl delete deployment <YOUR_DEPLOYMENT_NAME> && kubectl delete deployment <YOUR_SERVICE_NAME> && kubectl delete deployment <SECRET-NAME>

Summary

Kubernetes is the tool for you if you’re looking for a deployment tool that can provide automation, scalability, and management of a deployed application. This tutorial detailed a step-by-step walkthrough of deploying and accessing public and private images from a DockerHub account.

Next steps

Now that you know how to access your public and private images, make sure to regularly scan your images with the free IBM Cloud Image Scanning Service. This service will scan the provided container image for vulnerabilities using the IBM Cloud Vulnerability Advisor. The image must be publicly available via a docker pull command without any authentication or login required.

You can also explore more code examples on orchestrating your containers by going through our Container Orchestration Code Patterns.

If you’re interested in other alternatives to DockerHub, check out the IBM Cloud Container Registry, where you can securely store and share Docker images with other users by adding images to your namespace.