Deploy a Docker Image Application description

In this lab, we’re going to deploy the web component of the ParksMap application which is also called parksmap and uses OpenShift service discovery mechanism to discover the backend services deployed and shows their data on the map.

Road Show App 1

Exercise: Deploying your first Image

Let’s start by doing the simplest thing possible - get a plain old Docker-formatted image to run on OpenShift. This is incredibly simple to do. With it can be done directly from the web console.

Return to the web console:

Find your project-userXY project and click it. Next, click "Add to project" at the top of the screen.

There are several options, but we are only concerned with "Deploy Image". Click it. We will learn more about image streams and image stream tags later. For now, select the "Image Name" option, and copy/paste the following into the box:

docker.io/openshiftroadshow/parksmap:1.2.0

Your screen will end up looking something like this:

parksmap-image

Either press enter or click on the magnifying glass. OpenShift will then go out to the Docker registry specified and interrogate the image. You then are presented with some options to add things like environment variables, labels, and etc. — which we will learn about later.

For now, change the application name:

parksmap-image-options

Hit the blue "Create" button at the bottom of the screen and then click the "Continue to overview" link. Take a moment to look at the various messages that you now see on the overview page.

WINNING! These few steps are the only ones you need to run to get a "vanilla" Docker-formatted image deployed on OpenShift. This should work with any Docker-formatted image that follows best practices, such as defining an EXPOSE port, not needing to run specifically as the root user or other user name, and a single non-exiting CMD to execute on start.

Background: Containers and Pods

Before we start digging in we need to understand how containers and Pods are related. Given the morning sessions where we discussed the OpenShift platform and how it uses containers and Pods, we will not be covering the background on these technologies in this lab. Instead, we will dive right in and start using them.

In OpenShift, the smallest deployable unit is a Pod. A Pod is a group of one or more Docker containers deployed together and guaranteed to be on the same host. From the doc:

Each pod has its own IP address, therefore owning its entire port space, and containers within pods can share storage. Pods can be "tagged" with one or more labels, which are then used to select and manage groups of pods in a single operation.

Pods can contain multiple Docker instances. The general idea is for a Pod to contain a "server" and any auxiliary services you want to run along with that server. Examples of containers you might put in a Pod are, an Apache HTTPD server, a log analyzer, and a file service to help manage uploaded files.

Exercise: Examining the Pod

In the web console’s overview page you will see that there is a single Pod that was created by your actions. This Pod contains a single container, which happens to be the parks map application - a simple Spring Boot/Java application.

You can also examine Pods from the command line:

oc get pod

You should see output that looks similar to:

NAME               READY     STATUS    RESTARTS   AGE
parksmap-1-1m1bj   1/1       Running   0          21s

The above output lists all of the Pods in the current Project, including the Pod name, state, restarts, and uptime. Once you have a Pod’s name, you can get more information about the Pod using the oc get command. To make the output readable, I suggest changing the output type to YAML using the following syntax:

Note
Make sure you use the correct Pod name from your output.
oc get pod parksmap-1-1m1bj -o yaml

You should see something like the following output (which has been truncated due to space considerations of this workshop manual):

apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubernetes.io/created-by: |
      {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicationController","namespace":"project-ksoong","name":"parksmap-1","uid":"1c2d04a5-607f-11e7-bbc1-0682973451aa","apiVersion":"v1","resourceVersion":"4053485"}}
    kubernetes.io/limit-ranger: 'LimitRanger plugin set: cpu, memory request for container
      parksmap; cpu, memory limit for container parksmap'
    openshift.io/deployment-config.latest-version: "1"
    openshift.io/deployment-config.name: parksmap
    openshift.io/deployment.name: parksmap-1
    openshift.io/generated-by: OpenShiftWebConsole
    openshift.io/scc: restricted
  creationTimestamp: 2017-07-04T06:07:53Z
  generateName: parksmap-1-
  labels:
    app: parksmap
    deployment: parksmap-1
    deploymentconfig: parksmap
  name: parksmap-1-1m1bj
  namespace: project-ksoong
  resourceVersion: "4053517"
  selfLink: /api/v1/namespaces/project-ksoong/pods/parksmap-1-1m1bj
  uid: 1df132f9-607f-11e7-bbc1-0682973451aa
spec:
  containers:
  - image: docker.io/openshiftroadshow/parksmap@sha256:d6d321390e0c8db598b23bab6d65b126bf3d1e61a9de6515e3389951996c0369
    imagePullPolicy: IfNotPresent
    name: parksmap
    ports:
    - containerPort: 8080
      protocol: TCP
    resources:
      limits:
        cpu: 500m
        memory: 2Gi
      requests:
        cpu: 50m
        memory: 256Mi
    securityContext:
      capabilities:
        drop:
        - KILL
        - MKNOD
        - SETGID
        - SETUID
        - SYS_CHROOT
      privileged: false
      runAsUser: 1001440000
      seLinuxOptions:
        level: s0:c38,c17
    terminationMessagePath: /dev/termination-log
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-bpp6f
      readOnly: true
  dnsPolicy: ClusterFirst
  imagePullSecrets:
  - name: default-dockercfg-7qgr6
  nodeName: node2.na1.internal
  nodeSelector:
    env: users
  restartPolicy: Always
  securityContext:
    fsGroup: 1001440000
    seLinuxOptions:
      level: s0:c38,c17
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  volumes:
  - name: default-token-bpp6f
    secret:
      defaultMode: 420
      secretName: default-token-bpp6f
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: 2017-07-04T06:07:53Z
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: 2017-07-04T06:08:07Z
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: 2017-07-04T06:07:53Z
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: docker://6b76986902e73454e499e750a881b003166e1b096928037c0a94f0cb7fed7f1f
    image: docker.io/openshiftroadshow/parksmap@sha256:d6d321390e0c8db598b23bab6d65b126bf3d1e61a9de6515e3389951996c0369
    imageID: docker-pullable://docker.io/openshiftroadshow/parksmap@sha256:d6d321390e0c8db598b23bab6d65b126bf3d1e61a9de6515e3389951996c0369
    lastState: {}
    name: parksmap
    ready: true
    restartCount: 0
    state:
      running:
        startedAt: 2017-07-04T06:08:07Z
  hostIP: 192.199.0.125
  phase: Running
  podIP: 10.1.3.191
  startTime: 2017-07-04T06:07:53Z

The web interface also shows a lot of the same information on the Pod details page. If you click in the Pod circle, and then click the Pod name, you will find the details page. You can also get there by clicking "Applications", then "Pods", at the left, and then clicking the Pod name.

Getting the parks map image running may take a little while to complete. Each OpenShift node that is asked to run the image has to pull (download) it if the node does not already have it cached locally. You can check on the status of the image download and deployment in the Pod details page, or from the command line with the oc get pods command that you used before.

Background: A Little About the Docker Daemon

Whenever OpenShift asks the node’s Docker daemon to run an image, the Docker daemon will check to make sure it has the right "version" of the image to run. If it doesn’t, it will pull it from the specified registry.

Background: Services

Services provide a convenient abstraction layer inside OpenShift to find a group of like Pods. They also act as an internal proxy/load balancer between those Pods and anything else that needs to access them from inside the OpenShift environment. For example, if you needed more parks map servers to handle the load, you could spin up more Pods. OpenShift automatically maps them as endpoints to the Service, and the incoming requests would not notice anything different except that the Service was now doing a better job handling the requests.

When you asked OpenShift to run the image, it automatically created a Service for you. Remember that services are an internal construct. They are not available to the "outside world", or anything that is outside the OpenShift environment. That’s OK, as you will learn later.

The way that a Service maps to a set of Pods is via a system of Labels and Selectors. Services are assigned an eternal IP address and many ports and protocols can be mapped.

Now that we understand the basics of what a Service is, let’s take a look at the Service that was created for the image that we just deployed. In order to view the Services defined in your Project, enter in the following command:

oc get services

You should see output similar to the following:

NAME       CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
parksmap   172.30.32.109   <none>        8080/TCP   10m

In the above output, we can see that we have a Service named parksmap with an IP/Port combination of 172.30.32.109/8080TCP. Your IP address may be different, as each Service receives a unique IP address upon creation. Service IPs are eternal and never change for the life of the Service.

In the web console, service information is available by clicking "Applications" and then clicking "Services" in the "Networking" submenu.

You can also get more detailed information about a Service by using the following command to display the data in YAML:

oc get service parksmap -o yaml

You should see output similar to the following:

apiVersion: v1
kind: Service
metadata:
  annotations:
    openshift.io/generated-by: OpenShiftWebConsole
  creationTimestamp: 2017-07-04T06:07:50Z
  labels:
    app: parksmap
  name: parksmap
  namespace: project-ksoong
  resourceVersion: "4053462"
  selfLink: /api/v1/namespaces/project-ksoong/services/parksmap
  uid: 1bcd1db8-607f-11e7-bbc1-0682973451aa
spec:
  clusterIP: 172.30.32.109
  ports:
  - name: 8080-tcp
    port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    deploymentconfig: parksmap
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

Take note of the selector stanza. Remember it.

  • The Service has selector stanza that refers to deploymentconfig=parksmap.

  • The Pod has multiple Labels:

    • deploymentconfig=parksmap

    • app=parksmap

    • deployment=parksmap-1

Labels are just key/value pairs. Any Pod in this Project that has a Label that matches the Selector will be associated with the Service. To see this in action, issue the following command:

oc describe service parksmap

You should see something like the following output:

Name:			parksmap
Namespace:		project-ksoong
Labels:			app=parksmap
Selector:		deploymentconfig=parksmap
Type:			ClusterIP
IP:			172.30.32.109
Port:			8080-tcp	8080/TCP
Endpoints:		10.1.3.191:8080
Session Affinity:	None
No events.

You may be wondering why only one end point is listed. That is because there is only one Pod currently running. In the next lab, we will learn how to scale an application, at which point you will be able to see multiple endpoints associated with the Service.

results matching ""

    No results matching ""