OpenShift Create an Application from a Docker Image

From NovaOrdis Knowledge Base
Revision as of 23:26, 7 February 2018 by Ovidiu (talk | contribs) (→‎Overview)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Internal

Overview

A Docker image repository URL can be provided to oc new-app to create an application based on that image.

oc new-app <docker-repository-URL>

Example:

oc new-app docker.io/sonatype/nexus3:latest

This is roughly what happens during the application creation process:

Primitives

The utility creates an image stream, a deployment configuration and a service in the current project, and associate all of them with a single application by annotating them with the "app=<application-name>" label, where the application name is inferred from - and equal to - the name of the image repository given as argument.

1. Image Stream. The image stream name is set to the application name, and the object is associated with the application by the "app=<app-name> label.

apiVersion: v1
kind: ImageStream
metadata:
 labels:
   app: nexus3
 name: nexus3
spec:
 lookupPolicy:
   local: false
 tags:
   name: latest
   from:
     kind: DockerImage
     name: docker.io/sonatype/nexus3:latest
   referencePolicy:
     type: Source
Image Streams

2. Deployment Configuration The deployment configuration defines a selector that applied over pods, returns the number of pods that should match the replica count. It also defines a "rolling" deployment strategy by default. You may want to change that after the application primitives are first created. The deployment configuration includes the labels applied to the pod and pod's specification. The pod will consist of one container, which will be instantiated from the image specified as argument.

OpenShift performs an introspection of the image metadata and extracts the ports that should be exposed and the Docker data volumes needed, which are declaratively associated with persistent volumes:

"Id": "sha256:0b6b1bc88ccb767d128d87002d164ca1bd90ca0b7775aed3864504dcf8f968d8",
"Config": {
    ...
    "ExposedPorts": {
        "8081/tcp": {}
    },
    ...
    "Volumes": {
        "/nexus-data": {}
    },
     ...
}

By default, the deployment configuration declares an "emptyDir" volume, which is a temporary directory whose content will be lost upon pod recycling, so this is probably something you may want to change.

Finally, the deployment configuration contains metadata that says the redeployment will be attempted on configuration change and image change.

apiVersion: v1
kind: DeploymentConfig
metadata:
 name: nexus3
 labels:
   app: nexus3
spec:
 selector:
   app: nexus3
   deploymentconfig: nexus3
 strategy:
   type: Rolling
   rollingParams:
     ...
   activeDeadlineSeconds: 21600
 template:
   metadata:
     labels:
       app: nexus3
       deploymentconfig: nexus3
   spec:
     containers:
     - name: nexus3
       image: docker.io/sonatype/nexus3@sha256:1b1a581c76bf2a43112d4eea0077a73aadf234bb34a7b56f76fd5f3c1634dcaf
       imagePullPolicy: Always
       ports:
       - containerPort: 8081
         protocol: TCP
       volumeMounts:
       - name: nexus3-volume-1
         mountPath: /nexus-data
     dnsPolicy: ClusterFirst
     restartPolicy: Always
     schedulerName: default-scheduler
     terminationGracePeriodSeconds: 30
     volumes:
     - name: nexus3-volume-1
       emptyDir: {}
 test: false
 triggers:
 - type: ConfigChange
 - type: ImageChange
   imageChangeParams:
     automatic: true
     containerNames:
     - nexus3
     from:
       kind: ImageStreamTag
       name: nexus3:latest
       namespace: production-nexus
   
Deployment Configuration

3. Service

apiVersion: v1
kind: Service
metadata:
 name: nexus3
 labels:
   app: nexus3
spec:
 clusterIP: 172.30.73.18
 ports:
 - name: 8081-tcp
   port: 8081
   protocol: TCP
   targetPort: 8081
 selector:
   app: nexus3
   deploymentconfig: nexus3
 sessionAffinity: None
 type: ClusterIP
Service

Post-Creation Operations

Simply creating the application triggers a deployment, while the application is not ready yet to be deployed, so we disable the automatic deployment and drop what has already been deployed:

oc rollout pause dc nexus3
oc delete rc <rc-name>

Deleting the replication controller will also terminate the pod it started.

Change the Deployment Strategy

oc patch dc nexus3 --patch='{ "spec": { "strategy": { "type": "Recreate" }}}'

Don't I need to also change configuration?

Attach a Valid Persistence Volume

For this to work, a 2Gi or more persistent volume must be already provisioned and available.

Create the persistent volume claim:

echo "apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: production-nexus-pvc
spec:
 accessModes:
 - ReadWriteOnce
 resources:
   requests:
     storage: 2Gi" | oc create -f -

If an appropriate persistent volume exists, it will be immediately bound after the persistent volume claim creation.

Modify the deployment configuration to use the persistent volume claim:

oc set volumes dc/nexus3 --remove --name=nexus3-volume-1
oc set volumes dc/nexus3 --add --name=nexus-data --mount-path=/nexus-data/ --type persistentVolumeClaim --claim-name=production-nexus-pvc

Setup Resources

oc set resources dc/nexus3 --limits=memory=2Gi --requests=memory=1Gi

Setup the Readiness and Liveness Probes

oc set probe dc/nexus3 --readiness \
--failure-threshold 3 --initial-delay-seconds 120 \
--get-url=http://:8081/repository/maven-public/
oc set probe dc/nexus3 --liveness \
--failure-threshold 3 --initial-delay-seconds 120 \
-- echo ok

Expose the Service

oc expose service nexus3 --hostname=maven.apps.openshift.novaordis.io

Resume Rollout

oc rollout resume dc nexus3

Example

For more details on how to deploy a production-ready Nexus instance starting with oc new-app <nexus-image-url>, go to:

Deploy Nexus Based on a Standard Sonatype Docker Image