Part 4 of the EX180 series.
The Plan
We are going to have a look at the EX180 exam objectives for OpenShift and perform 4 hands-on tasks to get familiar with an application deployment process.
Exam Objectives: OpenShift
These are official EX180 objectives related to OpenShift (we have covered Podman objectives in the previous article).
You should have basic OpenShift knowledge.
You should be able to create applications in OpenShift:
- Create, manage and delete projects from a template, from source code, and from an image.
- Customise catalog template parameters.
- Specifying environment parameters.
- Expose public applications.
Troubleshoot applications in OpenShift
- Understand the description of application resources.
- Get application logs.
- Inspect running applications.
- Connecting to containers running in a pod.
- Copy resources to/from containers running in a pod.
What is OpenShift?
OpenShift is a Red Hat’s open-source container platform that is built on top of Kubernetes and provides additional services developed by Red Hat that do not come with vanilla Kubernetes, e.g. integrated developer workflow (CI/CD pipelines and s2i), a built-in metrics service, a WebUI, routes to expose services.
Now that we know what OpenShift is, let us get started.
OpenShift Task 1: Deploy a MySQL Application using OpenShift Templates
- OpenShift can be accessed on the following URL: https://api.crc.testing:6443.
- Login to OpenShift cluster with username developer and password developer.
- Create a new project called ex180task1 and use this project to deploy resources for this task.
- The OpenShift installer creates several templates by default. Use the mysql-ephemeral template to deploy a MySQL application to OpenShift.
- The name of the application should be database.
- Inspect the mysql-ephemeral template to work out what variables to pass during deployment.
- Set MySQL user to dbuser1.
- Set MySQL user password to dbpass1.
- Set MySQL database name to db1.
- Set MySQL administrator password dbadminpass1.
- Verify that the database db1 has been created.
Solution to OpenShift Task 1
Login to the OpenShift cluster and verify:
$ eval $(crc oc-env) $ oc login -u developer -p developer https://api.crc.testing:6443
$ oc whoami developer
Create a new project and verify:
$ oc new-project ex180task1
$ oc project Using project "ex180task1" on server "https://api.crc.testing:6443"
As mentioned in the task definition, OpenShift creates several templates by default in the openshift namespace. List all available templates:
$ oc get templates -n openshift NAME DESCRIPTION PARAMETERS OBJECTS cache-service Red Hat Data Grid is an in-memory, distributed key/value store. 8 (1 blank) 4 cakephp-mysql-example An example CakePHP application with a MySQL database. For more information ab... 21 (4 blank) 8 cakephp-mysql-persistent An example CakePHP application with a MySQL database. For more information ab... 22 (4 blank) 9 dancer-mysql-example An example Dancer application with a MySQL database. For more information abo... 18 (5 blank) 8 dancer-mysql-persistent An example Dancer application with a MySQL database. For more information abo... 19 (5 blank) 9 [...output truncated...] mariadb-ephemeral MariaDB database service, without persistent storage. For more information ab... 8 (3 generated) 3 mariadb-persistent MariaDB database service, with persistent storage. For more information about... 9 (3 generated) 4 mysql-ephemeral MySQL database service, without persistent storage. For more information abou... 8 (3 generated) 3 mysql-persistent MySQL database service, with persistent storage. For more information about u... 9 (3 generated) 4 nginx-example An example Nginx HTTP server and a reverse proxy (nginx) application that ser... 10 (3 blank) 5 [...output truncated...]
We see there is a template called mysql-ephemeral that we need to use to deploy a MySQL application.
There are two different ways that I’m aware of to list available parameters from a template. One is to describe a template using oc describe
command like this:
$ oc describe template mysql-ephemeral -n openshift | less
Another one is to use oc process
command like this:
$ oc process --parameters mysql-ephemeral -n openshift NAME DESCRIPTION GENERATOR VALUE MEMORY_LIMIT Maximum amount of memory the container can use. 512Mi NAMESPACE The OpenShift Namespace where the ImageStream resides. openshift DATABASE_SERVICE_NAME The name of the OpenShift Service exposed for the database. mysql MYSQL_USER Username for MySQL user that will be used for accessing the database. expression user[A-Z0-9]{3} MYSQL_PASSWORD Password for the MySQL connection user. expression [a-zA-Z0-9]{16} MYSQL_ROOT_PASSWORD Password for the MySQL root user. expression [a-zA-Z0-9]{16} MYSQL_DATABASE Name of the MySQL database accessed. sampledb MYSQL_VERSION Version of MySQL image to be used (8.0-el7, 8.0-el8, or latest). 8.0-el8
We can have a look at the YAML template definition as well. This gives us some idea of what the DeploymentConfig would do to deploy the application.
$ oc get template mysql-ephemeral -n openshift -o yaml
Deploy MySQL application from the template:
$ oc -n ex180task1 new-app \ --name=database \ --template=mysql-ephemeral \ --param=MYSQL_USER=dbuser1 \ --param=MYSQL_PASSWORD=dbpass1 \ --param=MYSQL_DATABASE=db1 \ --param=MYSQL_ROOT_PASSWORD=dbadminpass1
Expected output:
--> Deploying template "openshift/mysql-ephemeral" to project ex180task1 MySQL (Ephemeral) --------- MySQL database service, without persistent storage. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/8.0/root/usr/share/container-scripts/mysql/README.md. WARNING: Any data stored will be lost upon pod destruction. Only use this template for testing The following service(s) have been created in your project: mysql. Username: dbuser1 Password: dbpass1 Database Name: db1 Connection URL: mysql://mysql:3306/ For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/8.0/root/usr/share/container-scripts/mysql/README.md. * With parameters: * Memory Limit=512Mi * Namespace=openshift * Database Service Name=mysql * MySQL Connection Username=dbuser1 * MySQL Connection Password=dbpass1 * MySQL root user Password=dbadminpass1 * MySQL Database Name=db1 * Version of MySQL Image=8.0-el8 --> Creating resources ... secret "mysql" created service "mysql" created deploymentconfig.apps.openshift.io "mysql" created --> Success Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose service/mysql' Run 'oc status' to view your app.
Verify pod status:
$ oc get po NAME READY STATUS RESTARTS AGE mysql-1-deploy 0/1 Completed 0 110s mysql-1-wwdcl 1/1 Running 0 107s
Verify that the db1 database has been created. Connect to the MySQL pod, when inside the pod, login to MySQL to show databases:
$ oc exec -it po/mysql-1-wwdcl -- /bin/bash bash-4.4$ mysql -u dbuser1 -pdbpass1 -e "show databases;" mysql: [Warning] Using a password on the command line interface can be insecure. +--------------------+ | Database | +--------------------+ | db1 | | information_schema | +--------------------+ bash-4.4$ exit
The task is complete.
OpenShift Task 2: Deploy a MySQL Application from a Template File
- OpenShift can be accessed on the following URL: https://api.crc.testing:6443.
- Login to OpenShift cluster with username developer and password developer.
- Create a new project called ex180task2 and use this project to deploy resources for this task.
- Download OpenShift template from https://raw.githubusercontent.com/openshift/origin/master/examples/db-templates/mysql-persistent-template.json and save it to the mysql-persistent-template.json file.
- Create a new OpenShift template from the mysql-persistent-template.json file.
- Deploy a new MySQL application with persistent storage using the template file mysql-persistent-template.json.
- The name of the application should be persistentdb.
- Inspect the mysql-persistent template to work out what variables to pass during deployment.
- Set MySQL user to dbuser2.
- Set MySQL user password to dbpass2.
- Set MySQL database name to db2.
- Set MySQL administrator password dbadminpass2.
- Set volume space available for MySQL data to 1Gi.
- Verify that a persistent volume claim (PVC) has been created.
- Copy the
/etc/my.cnf
file from the MySQL pod to the host directory/tmp
.
Solution to OpenShift Task 2
Login to the OpenShift cluster and verify:
$ eval $(crc oc-env) $ oc login -u developer -p developer https://api.crc.testing:6443
$ oc whoami developer
Create a new project and verify:
$ oc new-project ex180task2
$ oc project Using project "ex180task2" on server "https://api.crc.testing:6443"
Download the template using curl
and save it to the mysql-persistent-template.json
file:
$ curl -sSf -o mysql-persistent-template.json \ https://raw.githubusercontent.com/openshift/origin/master/examples/db-templates/mysql-persistent-template.json
Create a template from the mysql-persistent-template.json
file:
$ oc -n ex180task2 create -f ./mysql-persistent-template.json
By default, the template will be created under the current project:
$ oc get templates NAME DESCRIPTION PARAMETERS OBJECTS mysql-persistent MySQL database service, with persistent storage. For more information about u... 9 (3 generated) 4
Get environment variables defined in the template:
$ oc process --parameters mysql-persistent NAME DESCRIPTION GENERATOR VALUE MEMORY_LIMIT Maximum amount of memory the container can use. 512Mi NAMESPACE The OpenShift Namespace where the ImageStream resides. openshift DATABASE_SERVICE_NAME The name of the OpenShift Service exposed for the database. mysql MYSQL_USER Username for MySQL user that will be used for accessing the database. expression user[A-Z0-9]{3} MYSQL_PASSWORD Password for the MySQL connection user. expression [a-zA-Z0-9]{16} MYSQL_ROOT_PASSWORD Password for the MySQL root user. expression [a-zA-Z0-9]{16} MYSQL_DATABASE Name of the MySQL database accessed. sampledb VOLUME_CAPACITY Volume space available for data, e.g. 512Mi, 2Gi. 1Gi MYSQL_VERSION Version of MySQL image to be used (8.0-el7, 8.0-el8, or latest). 8.0-el8
We see that the variable used to define volume space is called VOLUME_CAPACITY.
Deploy MySQL application from the template file mysql-persistent-template.json
:
$ oc -n ex180task2 new-app \ --name=persistentdb \ --file=mysql-persistent-template.json \ --param=MYSQL_USER=dbuser2 \ --param=MYSQL_PASSWORD=dbpass2 \ --param=MYSQL_DATABASE=db2 \ --param=MYSQL_ROOT_PASSWORD=dbadminpass2 \ --param=VOLUME_CAPACITY=1Gi
Expected output:
--> Deploying template "ex180task2/mysql-persistent" for "mysql-persistent-template.json" to project ex180task2 MySQL --------- MySQL database service, with persistent storage. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/8.0/root/usr/share/container-scripts/mysql/README.md. NOTE: Scaling to more than one replica is not supported. You must have persistent volumes available in your cluster to use this template. The following service(s) have been created in your project: mysql. Username: dbuser2 Password: dbpass2 Database Name: db2 Connection URL: mysql://mysql:3306/ For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/8.0/root/usr/share/container-scripts/mysql/README.md. * With parameters: * Memory Limit=512Mi * Namespace=openshift * Database Service Name=mysql * MySQL Connection Username=dbuser2 * MySQL Connection Password=dbpass2 * MySQL root user Password=dbadminpass2 * MySQL Database Name=db2 * Volume Capacity=1Gi * Version of MySQL Image=8.0-el8 --> Creating resources ... secret "mysql" created service "mysql" created persistentvolumeclaim "mysql" created deploymentconfig.apps.openshift.io "mysql" created --> Success Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose service/mysql' Run 'oc status' to view your app.
Verify pod status:
$ oc get po NAME READY STATUS RESTARTS AGE mysql-1-deploy 0/1 Completed 0 2m25s mysql-1-zdks7 1/1 Running 0 2m22s
List persistent volume claims:
$ oc get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mysql Bound pv0004 100Gi RWO,ROX,RWX 2m50s
Copy /etc/my.cnf
from a remote pod to /tmp/my.cnf
locally:
$ oc cp mysql-1-zdks7:/etc/my.cnf /tmp/my.cnf
This task is complete.
OpenShift Task 3: Deploy a PHP Application using Source-to-Image (S2I)
- OpenShift can be accessed on the following URL: https://api.crc.testing:6443.
- Login to OpenShift cluster with username developer and password developer.
- Create a new project called ex180task3 and use this project to deploy resources for this task.
- Create a new PHP Hello World application using S2I deployment.
- The name of the application should be helloworld.
- The source code is available from the Git repository at https://github.com/lisenet/DO180-apps/ in the php-helloworld directory.
- Use the development branch of the Git repository.
- Use the php:7.3 image stream tag.
- Expose the PHP application’s service to make the application accessible from a web browser.
Solution to OpenShift Task 3
Login to the OpenShift cluster and verify:
$ eval $(crc oc-env) $ oc login -u developer -p developer https://api.crc.testing:6443
$ oc whoami developer
Create a new project and verify:
$ oc new-project ex180task3
$ oc project Using project "ex180task3" on server "https://api.crc.testing:6443"
Deploy a new PHP application using S2I:
$ oc -n ex180task3 new-app \ --name helloworld \ -i php:7.3 https://github.com/lisenet/DO180-apps#development \ --context-dir php-helloworld
Expected output:
--> Found image 70d4d94 (2 months old) in image stream "openshift/php" under tag "7.3" for "php:7.3" Apache 2.4 with PHP 7.3 ----------------------- PHP 7.3 available as container is a base platform for building and running various PHP 7.3 applications and frameworks. PHP is an HTML-embedded scripting language. PHP attempts to make it easy for developers to write dynamically generated web pages. PHP also offers built-in database integration for several commercial and non-commercial database management systems, so writing a database-enabled webpage with PHP is fairly simple. The most common use of PHP coding is probably as a replacement for CGI scripts. Tags: builder, php, php73, rh-php73 * The source repository appears to match: php * A source build using source code from https://github.com/lisenet/DO180-apps#development will be created * The resulting image will be pushed to image stream tag "helloworld:latest" * Use 'oc start-build' to trigger a new build --> Creating resources ... imagestream.image.openshift.io "helloworld" created buildconfig.build.openshift.io "helloworld" created Warning: would violate PodSecurity "restricted:v1.24": allowPrivilegeEscalation != false (container "helloworld" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "helloworld" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "helloworld" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "helloworld" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost") deployment.apps "helloworld" created service "helloworld" created --> Success Build scheduled, use 'oc logs -f buildconfig/helloworld' to track its progress. Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose service/helloworld' Run 'oc status' to view your app.
Check the build config:
$ oc get bc NAME TYPE FROM LATEST helloworld Source Git@development 1
Check the service:
$ oc get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE helloworld ClusterIP 10.217.4.118 none 8080/TCP,8443/TCP 37s
Check the image stream:
$ oc get is NAME IMAGE REPOSITORY TAGS UPDATED helloworld default-route-openshift-image-registry.apps-crc.testing/ex180task3/helloworld latest About a minute ago
Check the pods:
$ oc get po NAME READY STATUS RESTARTS AGE helloworld-1-build 0/1 Completed 0 3m3s helloworld-66879f45bc-gfc7h 1/1 Running 0 109s
Note: you can use oc get all
command to list all resources.
Expose the PHP application:
$ oc expose svc helloworld
Make sure that the route resource has been created:
$ oc get routes NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD helloworld helloworld-ex180task3.apps-crc.testing helloworld 8080-tcp None
Access the application with curl
:
$ curl http://helloworld-ex180task3.apps-crc.testing Hello, World! php version is 7.3.33 This is development branch
This task is complete.
OpenShift Task 4: Deploy an HTTP Application from Image
- OpenShift can be accessed on the following URL: https://api.crc.testing:6443.
- Login to OpenShift cluster with username developer and password developer.
- Create a new project called app-from-image and use this project to deploy resources for this task.
- Deploy a new web application using the image you have built for the Podman task 4. Use private image quay.io/$USERNAME/httpd:1.0-test, where $USERNAME is your quay.io username.
- Create an OpenShift secret called my-quay-credentials for use with a container registry, and use your quay.io credentials. Use this secret to deploy the application from the private registry.
- The name of the application should be webserver.
- Add the following label to all resources: task=4.
- Create the application as a deployment config.
- Troubleshoot and identify the reason why the pod is failing to start.
- Delete the project from OpenShift.
Solution to OpenShift Task 4
Login to the OpenShift cluster and verify:
$ eval $(crc oc-env) $ oc login -u developer -p developer https://api.crc.testing:6443
$ oc whoami developer
Create a new project and verify:
$ oc new-project app-from-image
$ oc project Using project "app-from-image" on server "https://api.crc.testing:6443".
Check documentation for how to create a new secret:
$ oc create secret --help
Create a new secret to store quay.io credentials:
$ oc -n app-from-image create secret docker-registry my-quay-credentials \ --docker-server=quay.io \ --docker-username=YOUR_QUAY_USERNAME \ --docker-password=YOUR_QUAY_PASSWORD \ --docker-email=YOUR_QUAY_EMAIL
Verify that the secret has been created:
$ oc get secret my-quay-credentials -o yaml apiVersion: v1 data: .dockerconfigjson: eyJhdXRocyI6eyJxdWF5LmlvIjp7InVzZXJuYW1lIjoiWU9VUl9RVUFZX1VTRVJOQU1FIiwicGFzc3dvcmQiOiJZT1VSX1FVQVlfUEFTU1dPUkQiLCJlbWFpbCI6IllPVVJfUVVBWV9FTUFJTCIsImF1dGgiOiJXVTlWVWw5UlZVRlpYMVZUUlZKT1FVMUZPbGxQVlZKZlVWVkJXVjlRUVZOVFYwOVNSQT09In19fQ== kind: Secret metadata: creationTimestamp: "2022-11-27T18:50:40Z" name: my-quay-credentials namespace: app-from-image resourceVersion: "161791" uid: 918119ae-1f6c-455d-8002-73bcb4bfbef3 type: kubernetes.io/dockerconfigjson
Optionally, we could decode the data by using base64 -d
if we wanted to see the credentials.
To use the secret for pulling images for pods, we must add the secret to the default service account, because the service account that the pod uses is the default service account.
Link secrets to a service account:
$ oc secrets link default my-quay-credentials --for=pull
Next we can check documentation for how to add labels to resource and use a deployment config:
$ oc new-app --help | less
Create the webserver application using the httpd image from a private registry and specify the existing secret to use:
$ oc -n app-from-image new-app \ --name webserver \ --labels=task=4 \ --as-deployment-config=true \ --image=quay.io/lisenet/httpd:1.0-test
Expected output:
--> Found container image 8653efc (12 days old) from quay.io for "quay.io/lisenet/httpd:1.0-test" * An image stream tag will be created as "webserver:1.0-test" that will track this image * This image will be deployed in deployment config "webserver" * Port 80/tcp will be load balanced by service "webserver" * Other containers can access this service through the hostname "webserver" * WARNING: Image "quay.io/lisenet/httpd:1.0-test" runs as the 'root' user which may not be permitted by your cluster administrator --> Creating resources with label task=4 ... imagestream.image.openshift.io "webserver" created deploymentconfig.apps.openshift.io "webserver" created service "webserver" created --> Success Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 'oc expose service/webserver' Run 'oc status' to view your app.
Get deployment config:
$ oc get dc NAME REVISION DESIRED CURRENT TRIGGERED BY webserver 1 1 1 config,image(webserver:1.0-test)
Get pod status including labels:
$ oc get po NAME READY STATUS RESTARTS AGE LABELS webserver-1-deploy 0/1 Completed 0 17m openshift.io/deployer-pod-for.name=webserver-1 webserver-1-kc22v 0/1 CrashLoopBackOff 7 (4m26s ago) 17m deployment=webserver-1,deploymentconfig=webserver,task=4
We see that the webserver pod status is CrashLoopBackOff.
Get the cluster events to see if anything is failing:
$ oc get events
Get the webserver pod logs:
$ oc logs po/webserver-1-kc22v AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.217.0.173. Set the 'ServerName' directive globally to suppress this message (13)Permission denied: AH00072: make_sock: could not bind to address [::]:80 (13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80 no listening sockets available, shutting down AH00015: Unable to open logs
It looks like the container is trying to bind to a privileged port 80, but is not allowed to do so. The task did not ask us to resolve the problem, but identify the cause.
Delete the project:
$ oc delete project app-from-image
The task is complete.
Hi there, I get the following error when trying to execute the first task creating the application on OpenShift.
error: error processing template “openshift/mysql-ephemeral”: the namespace of the provided object does not match the namespace sent on the request