{"id":93,"date":"2023-05-18T17:12:03","date_gmt":"2023-05-18T15:12:03","guid":{"rendered":"https:\/\/blog.openshift.one\/?p=93"},"modified":"2023-05-18T21:27:40","modified_gmt":"2023-05-18T19:27:40","slug":"a-simple-demo-of-containers-and-a-vm-working-together","status":"publish","type":"post","link":"https:\/\/blog.openshift.one\/index.php\/2023\/05\/18\/a-simple-demo-of-containers-and-a-vm-working-together\/","title":{"rendered":"A simple demo of containers and a VM working together"},"content":{"rendered":"\n<p>The purpose of this exercise is to demonstrate how containers and virtual machines can work together. Additionally I also demonstrate a bit of security topic in the container world.<\/p>\n\n\n\n<p>I will create a simple service which include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>OpenShift Route \/ Load Balancer<\/li>\n\n\n\n<li>Containerised WordPress based on the official image with small modification<\/li>\n\n\n\n<li>Virtual machine running Linux with MariaDB as a backend for WordPress blog<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.openshift.one\/wp-content\/uploads\/2023\/05\/wordpress-ocpv.png\" alt=\"\" class=\"wp-image-113\" width=\"396\" height=\"632\" srcset=\"https:\/\/blog.openshift.one\/wp-content\/uploads\/2023\/05\/wordpress-ocpv.png 528w, https:\/\/blog.openshift.one\/wp-content\/uploads\/2023\/05\/wordpress-ocpv-188x300.png 188w\" sizes=\"auto, (max-width: 396px) 100vw, 396px\" \/><\/figure>\n\n\n\n<p>To make the exercise more interesting I decided that every single step will be done in CLI. In general, depends on the task it may be convenient to use either WebUI or command line but in this case I will focus only on text console. <\/p>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Requirements:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Running OpenShift Container Platform (<a href=\"https:\/\/docs.openshift.com\/container-platform\/4.12\/getting_started\/openshift-overview.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/docs.openshift.com\/container-platform\/4.12\/getting_started\/openshift-overview.html<\/a>)<\/li>\n\n\n\n<li>Installed and running OpenShift Virtualisation Operator (<a href=\"https:\/\/docs.openshift.com\/container-platform\/4.12\/virt\/about-virt.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/docs.openshift.com\/container-platform\/4.12\/virt\/about-virt.html<\/a>)<\/li>\n\n\n\n<li>Installed and running OpenShift Data Foundation Operator (<a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_openshift_data_foundation\/4.12\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_openshift_data_foundation\/4.12<\/a>)<\/li>\n\n\n\n<li>Working end exposed internal OpenShift Image Registry (<a href=\"https:\/\/docs.openshift.com\/container-platform\/4.12\/registry\/securing-exposing-registry.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/docs.openshift.com\/container-platform\/4.12\/registry\/securing-exposing-registry.html<\/a>)<\/li>\n\n\n\n<li>Installed <code>oc<\/code> and <code>virtctl<\/code> CLI tools (<a href=\"https:\/\/docs.openshift.com\/container-platform\/4.12\/cli_reference\/openshift_cli\/getting-started-cli.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/docs.openshift.com\/container-platform\/4.12\/cli_reference\/openshift_cli\/getting-started-cli.html<\/a>)<\/li>\n<\/ul>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Project wordpress-demo<\/h3>\n\n\n\n<p>Firstly I will create a new project called <em>wordpress-demo<\/em> where the blog application will be running:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc new-project wordpress-demo\nNow using project \"wordpress-demo\" on server \"https:\/\/api.ocp4.example.com:6443\".\n\nYou can add applications to this project with the 'new-app' command. For example, try:\n\n    oc new-app rails-postgresql-example\n\nto build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:\n\n    kubectl create deployment hello-node --image=k8s.gcr.io\/e2e-test-images\/agnhost:2.33 -- \/agnhost serve-hostname<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Creating VM in OpenShift<\/h3>\n\n\n\n<p>When creating virtual machine in OpenShift using WebUI is much more convenient than CLI, but I believe knowing the both ways is the best option. I use OpenShift&#8217;s template <em>rhel9-server-small<\/em> from <em>openshift<\/em> namespace to create simple VM with RHEL9. These templates among the others come out of the box with OpenShift Virtualization operator. Please note the VM is not automatically started after creation:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc process -n openshift rhel9-server-small -p NAME=wordpress-db | oc create -f -\nvirtualmachine.kubevirt.io\/wordpress-db created\n\n$ oc get vm\nNAME           AGE   STATUS    READY\nwordpress-db   25s   Stopped   False\n\n$ virtctl start wordpress-db\nVM wordpress-db was scheduled to start\n\n$ oc get vm,vmi\nNAME                                      AGE   STATUS    READY\nvirtualmachine.kubevirt.io\/wordpress-db   70s   Running   True\n\nNAME                                              AGE   PHASE     IP             NODENAME   READY\nvirtualmachineinstance.kubevirt.io\/wordpress-db   28s   Running   10.129.1.104   master-1   True<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Virtual machine user credentials<\/h3>\n\n\n\n<p>Because I didn&#8217;t specify <code>CLOUD_USER_PASSWORD<\/code> parameter while processing the template and creating the VM, <em>cloud_user <\/em>password has been automatically generated for me. I could retrieve it in various ways but this time I want to challenge myself and do everything in CLI, therefore I ran the following command to get it from the VM resource:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc get vm wordpress-db -o json  | jq -r '.spec.template.spec.volumes&#91;] | select(.name | contains(\"cloudinitdisk\")) | .cloudInitNoCloud.userData'\n#cloud-config\nuser: cloud-user\npassword: maa1-4jpj-6m77\nchpasswd: { expire: False }<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Connecting to the VM<\/h3>\n\n\n\n<p>To get access to the VM console I use <code>virtctl<\/code> CLI tool and credentials from the above. Once I got in I enabled password authentication for sshd and restarted it so I can ssh to the VM directly:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ virtctl console wordpress-db\nSuccessfully connected to wordpress-db console. The escape sequence is ^]\n\nwordpress-db login: cloud-user\nPassword:\n&#91;cloud-user@wordpress-db ~]$ sudo su\n\n&#91;root@wordpress-db ~]# sed -i 's\/^PasswordAuthentication no\/\/g' \/etc\/ssh\/sshd_config\n\n&#91;root@wordpress-db ~]# systemctl restart sshd<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>But&#8230; wait a moment! How am I supposed to ssh there?<br>Since VM in OpenShift Virtualisation is running in a container it inherits network attachments too. I don&#8217;t have any extra networks defined here so I will use <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.openshift.com\/container-platform\/4.12\/networking\/configuring_ingress_cluster_traffic\/configuring-ingress-cluster-traffic-nodeport.html\" target=\"_blank\">NodePort<\/a> service type in order to get connected to the VM. <code>virtctl<\/code> tool is very handy to create it for a virtual machine:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ virtctl expose vm wordpress-db --port=22 --name=wordpress-db-ssh --type=NodePort\nService wordpress-db-ssh successfully exposed for vm wordpress-db<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Since I use a NodePort, OpenShift creates for me random port forwarding rule on all the nodes running in the cluster to let me access the VM. The random port number can be retrieved from service definition:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc get svc wordpress-db-ssh\nNAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE\nwordpress-db-ssh   <strong>NodePort<\/strong>   172.30.31.216   &lt;none&gt;        22:<strong>32163<\/strong>\/TCP   3m5s<\/code><\/pre>\n\n\n\n<p>or in a bit more fancy way:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc get svc wordpress-db-ssh -o json | jq '.spec.ports&#91;] | select(.port | contains(22)).nodePort'\n<strong>32163<\/strong><\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Now I need the IP address to connect to. Since this is NodePort type service we can connect to any of the nodes in the cluster and the connection will be redirected through default cluster network to the VM. Let&#8217;s get the IPs of all nodes:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc get nodes -o custom-columns=NODE:.metadata.name,IP:.status.addresses&#91;].address\nNODE       IP\nmaster-1   <strong>192.168.232.123<\/strong>\nmaster-2   <strong>192.168.232.124<\/strong>\nmaster-3   <strong>192.168.232.122<\/strong><\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>With IP address and port number I can finally get access to the VM:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ ssh cloud-user@192.168.232.123 -p 32163\ncloud-user@192.168.232.123's password:\nRegister this system with Red Hat Insights: insights-client --register\nCreate an account or view all your systems at https:\/\/red.ht\/insights-dashboard\n&#91;cloud-user@wordpress-db ~]$<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Because it is just another virtual machine running under QEMU-KVM, there is nothing really new for those familiar with virtualisation. Let&#8217;s get it registered with Red Hat and install MariaDB on it, preferably this should be done with some sort of automation but that&#8217;s not the aim for this practice.<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>&#91;cloud-user@wordpress-db ~]$ sudo subscription-manager register --org &lt;&lt;ORG_ID&gt;&gt; --activationkey &lt;&lt;KEY&gt;&gt;\nThe system has been registered with ID: aaa-eee-ffff-ccc\nThe registered system name is: wordpress-db\nInstalled Product Current Status:\nProduct Name: Red Hat Enterprise Linux for x86_64\nStatus:       Subscribed\n\n&#91;cloud-user@wordpress-db ~]$ sudo dnf install -y mariadb-server\nUpdating Subscription Management repositories.\nRed Hat Enterprise Linux 9 for x86_64 - AppStream (RPMs)                                                                              9.4 MB\/s |  21 MB     00:02\nRed Hat Enterprise Linux 9 for x86_64 - BaseOS (RPMs)\n(...)\nComplete!\n\n&#91;cloud-user@wordpress-db ~]$ sudo systemctl enable --now mariadb\nCreated symlink \/etc\/systemd\/system\/mysql.service \u2192 \/usr\/lib\/systemd\/system\/mariadb.service.\nCreated symlink \/etc\/systemd\/system\/mysqld.service \u2192 \/usr\/lib\/systemd\/system\/mariadb.service.\nCreated symlink \/etc\/systemd\/system\/multi-user.target.wants\/mariadb.service \u2192 \/usr\/lib\/systemd\/system\/mariadb.service.<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Create a database and a user <code>wordpress_user<\/code> with password <code>wordpress_password<\/code>. Please write down that somewhere as it will be needed when configuring WordPress.<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>&#91;cloud-user@wordpress-db ~]$ echo \"create database wordpress; grant all on wordpress.* to 'wordpress_user'@'%' identified by 'wordpress_password'; flush privileges;\" | sudo mysql<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>The last thing I still need to do is exposing MariaDB port so pods (containers) can access it. Again I will use <code>virtctl<\/code> CLI. Please note missing <code>--type=NodePort<\/code> parameter. This is because the default type (<em>ClusterIP<\/em>) is enough as we don&#8217;t expect &#8211; at least now &#8211; to have a need to connect to MariaDB from outside the cluster.<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ virtctl expose vm wordpress-db --port=3306 --name=wordpress-db-mariadb\nService wordpress-db-mariadb successfully exposed for vm wordpress-db\n\n$ oc describe svc wordpress-db-mariadb\nName:              wordpress-db-mariadb\nNamespace:         wordpress-demo\nLabels:            &lt;none&gt;\nAnnotations:       &lt;none&gt;\nSelector:          kubevirt.io\/domain=wordpress-db,kubevirt.io\/size=small\nType:              ClusterIP\nIP Family Policy:  SingleStack\nIP Families:       IPv4\nIP:                172.30.106.220\nIPs:               172.30.106.220\nPort:              &lt;unset&gt;  3306\/TCP\nTargetPort:        3306\/TCP\nEndpoints:         10.129.1.104:3306\nSession Affinity:  None\nEvents:            &lt;none&gt;<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>The virtual machine is ready now, let&#8217;s do some containerisation work.<\/p>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Containers &#8211; original WordPress image<\/h3>\n\n\n\n<p>WordPress provides official Docker image available at https:\/\/hub.docker.com\/_\/wordpress to speedup the process a bit. It contains integration making running it in a container straightforward but&#8230; let me show you.<\/p>\n\n\n\n<p>I created a deploymend using <code>oc new-app<\/code> command as bellow:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc new-app --image=docker.io\/wordpress:php8.2-apache --name=wordpress-frontend -e WORDPRESS_DB_HOST=wordpress-db-mariadb -e WORDPRESS_DB_USER=wordpress_user -e WORDPRESS_DB_PASSWORD=wordpress_password -e WORDPRESS_DB_NAME=wordpress\n--&gt; Found container image 5835e3b (32 hours old) from docker.io for \"docker.io\/wordpress:php8.2-apache\"\n\n    * An image stream tag will be created as \"wordpress-frontend:php8.2-apache\" that will track this image\n\n--&gt; Creating resources ...\n    imagestream.image.openshift.io \"wordpress-frontend\" created\nWarning: would violate PodSecurity \"restricted:v1.24\": allowPrivilegeEscalation != false (container \"wordpress-frontend\" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container \"wordpress-frontend\" must set securityContext.capabilities.drop=&#91;\"ALL\"]), runAsNonRoot != true (pod or container \"wordpress-frontend\" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container \"wordpress-frontend\" must set securityContext.seccompProfile.type to \"RuntimeDefault\" or \"Localhost\")\n    deployment.apps \"wordpress-frontend\" created\n    service \"wordpress-frontend\" created\n--&gt; Success\n    Application is not exposed. You can expose services to the outside world by executing one or more of the commands below:\n     'oc expose service\/wordpress-frontend'\n    Run 'oc status' to view your app.<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>So far so good, let me check the app status as the command above suggest:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc status\nIn project wordpress-demo on server https:\/\/api.ocp4.example.com:6443\n\nsvc\/wordpress-db-ssh (all nodes):32163 -&gt; 22\nsvc\/wordpress-db-mariadb - 172.30.106.220:3306\n  pod\/virt-launcher-wordpress-db-75b8w runs registry.redhat.io\/container-native-virtualization\/virt-launcher@sha256:1ee29ef3f8b117bef13ba4325b597da99b55a1acb5f2e9eabe11937e9314fe73\n\nsvc\/wordpress-frontend - 172.30.78.10:80\n  deployment\/wordpress-frontend deploys istag\/wordpress-frontend:php8.2-apache\n    deployment #2 running for about a minute - 0\/1 pods (warning: 3 restarts)\n    deployment #1 deployed about a minute ago\n\nErrors:\n  * pod\/wordpress-frontend-5d467d8899-wn8v9 is crash-looping\n\n1 error, 1 info identified, use 'oc status --suggest' to see details.<\/code><\/pre>\n\n\n\n<div style=\"height:35px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Ooops! The pod is crash-looping what indicates successful download\/import to the cluster but while running it fails for some unknown yet reason. Let&#8217;s see what OpenShift would suggest me to do:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc status --suggest\n(...)\nErrors:\n  * pod\/wordpress-frontend-5d467d8899-wn8v9 is crash-looping\n\n    The container is starting and exiting repeatedly. This usually means the container is unable\n    to start, misconfigured, or limited by security restrictions. Check the container logs with\n\n      oc logs wordpress-frontend-5d467d8899-wn8v9 -c wordpress-frontend\n\n    Current security policy prevents your containers from being run as the root user. Some images\n    may fail expecting to be able to change ownership or permissions on directories. Your admin\n    can grant you access to run containers that need to run as the root user with this command:\n\n      oc adm policy add-scc-to-user anyuid -n wordpress-demo -z default\n(...)<\/code><\/pre>\n\n\n\n<div style=\"height:35px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Ok that may be the case. I don&#8217;t like the advice though to level up privileges. Let&#8217;s investigate it further and check for any output logs on the container:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc logs wordpress-frontend-5d467d8899-wn8v9 -c wordpress-frontend\nAH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.129.1.49. Set the 'ServerName' directive globally to suppress this message\n(13)Permission denied: AH00072: make_sock: could not bind to address &#91;::]:80\n(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80\nno listening sockets available, shutting down\nAH00015: Unable to open logs<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Gotcha! As you can see, the wordpress image wants to bind to port 80\/tcp for what it would require extra privileges. This isn&#8217;t something what I&#8217;d like to have running on my cluster due to the obvious security concerns. Therefore I will slightly modify the original docker image and adapt it for being used on OpenShift. Simultaneously I will increase its security level too! \ud83d\ude09 <\/p>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Containers &#8211; custom WordPress image<\/h3>\n\n\n\n<p>Firstly let&#8217;s clean up the failed deployment to ensure it won&#8217;t interfere in any way with the later one.<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc delete all -l app=wordpress-frontend\nservice \"wordpress-frontend\" deleted\ndeployment.apps \"wordpress-frontend\" deleted\nimagestream.image.openshift.io \"wordpress-frontend\" deleted<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Because container images are layered, I can use the original image &#8211; <code>docker.io\/wordpress:php8.2-apache<\/code> &#8211; and apply some changes to it to produce new, custom one. I&#8217;ve quickly reviewed what&#8217;s inside the original image and how its original Dockerfile looks like. This brought me to the conclusion that the following simple Containerfile will fix the issue and let me run WordPress container as unprivileged. I use podman instead of docker, hence I use Containerfile in place of Dockerfile, the syntax is the same:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ cat &lt;&lt; EOF &gt; Containerfile\nFROM docker.io\/wordpress:php8.2-apache\n\nRUN sed -i 's\/^Listen\\ 80$\/Listen\\ 8080\/' \/etc\/apache2\/ports.conf\n\nEXPOSE 8080\nENTRYPOINT &#91;\"\/usr\/local\/bin\/docker-entrypoint.sh\"]\nCMD &#91;\"apache2-foreground\"]\nEOF<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Now I will build and tag the image. I&#8217;m using my OpenShift&#8217;s internal registry route which let me upload images from outside the cluster:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ podman build -t default-route-openshift-image-registry.apps.ocp4.example.com\/wordpress-demo\/wordpress .\nSTEP 1\/5: FROM docker.io\/wordpress:php8.2-apache\nSTEP 2\/5: RUN sed -i 's\/^Listen\\ 80$\/Listen\\ 8080\/' \/etc\/apache2\/ports.conf\n--&gt; c511c5645d3\nSTEP 3\/5: EXPOSE 8080\n--&gt; 3a27ae7062a\nSTEP 4\/5: ENTRYPOINT &#91;\"\/usr\/local\/bin\/docker-entrypoint.sh\"]\n--&gt; d75fd350f4a\nSTEP 5\/5: CMD &#91;\"apache2-foreground\"]\nCOMMIT default-route-openshift-image-registry.apps.ocp4.example.com\/wordpress-demo\/wordpress\n--&gt; 945945a1c24\nSuccessfully tagged default-route-openshift-image-registry.apps.ocp4.example.com\/wordpress-demo\/wordpress:latest\n945945a1c24a9e8620d33c2eca01a98e1d796911868536dcf32c9ac92843e3cc<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>How to configure external access for OpenShift internal image registry you can find in this document: <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.openshift.com\/container-platform\/4.12\/registry\/securing-exposing-registry.html\" target=\"_blank\">https:\/\/docs.openshift.com\/container-platform\/4.12\/registry\/securing-exposing-registry.html<\/a><\/p>\n\n\n\n<p>Time to push the image to the registry:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ podman push default-route-openshift-image-registry.apps.ocp4.example.com\/wordpress-demo\/wordpress\nGetting image source signatures\n(...)\nCopying blob f675495821b9 done\n(...)\nCopying config 945945a1c2 done\nWriting manifest to image destination\nStoring signatures<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>And create ImageStream pointing to that image. To learn more about ImageStreams please see <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.openshift.com\/container-platform\/4.12\/openshift_images\/image-streams-manage.html\" target=\"_blank\">Managing image streams<\/a> chapter in Red Hat&#8217;s OpenShift documentation.<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc tag image-registry.openshift-image-registry.svc.cluster.local\/wordpress-demo\/wordpress:latest wordpress-demo\/wordpress:latest\nTag wordpress:latest set to image-registry.openshift-image-registry.svc.cluster.local\/wordpress-demo\/wordpress:latest<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Now I can again create <em>wordpress-frontend<\/em> deployment using <code>oc new-app<\/code> command, this time using my own customised wordpress image (through the ImageStream).<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc new-app --image-stream=wordpress:latest --name=wordpress-frontend -e WORDPRESS_DB_HOST=wordpress-db-mariadb -e WORDPRESS_DB_USER=wordpress_user -e WORDPRESS_DB_PASSWORD=wordpress_password -e WORDPRESS_DB_NAME=wordpress\n--&gt; Found image 945945a (5 minutes old) in image stream \"wordpress-demo\/wordpress\" under tag \"latest\" for \"wordpress:latest\"\n\n\n--&gt; Creating resources ...\nWarning: would violate PodSecurity \"restricted:v1.24\": allowPrivilegeEscalation != false (container \"wordpress\" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container \"wordpress\" must set securityContext.capabilities.drop=&#91;\"ALL\"]), runAsNonRoot != true (pod or container \"wordpress\" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container \"wordpress\" must set securityContext.seccompProfile.type to \"RuntimeDefault\" or \"Localhost\")\n    deployment.apps \"wordpress-frontend\" created\n    service \"wordpress-frontend\" created\n--&gt; Success\n    Application is not exposed. You can expose services to the outside world by executing one or more of the commands below:\n     'oc expose service\/wordpress-frontend'\n    Run 'oc status' to view your app.<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Let&#8217;s verify the status as the output above suggests<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc status\nIn project wordpress-demo on server https:\/\/api.ocp4.example.com:6443\n\nsvc\/wordpress-db-ssh (all nodes):32163 -&gt; 22\nsvc\/wordpress-db-mariadb - 172.30.106.220:3306\n  pod\/virt-launcher-wordpress-db-75b8w runs registry.redhat.io\/container-native-virtualization\/virt-launcher@sha256:1ee29ef3f8b117bef13ba4325b597da99b55a1acb5f2e9eabe11937e9314fe73\n\nsvc\/wordpress-frontend - 172.30.85.119 ports 80, 8080\n  deployment\/wordpress-frontend deploys istag\/wordpress:latest\n    deployment #1 running for 5 minutes - 1 pod (warning: 1 restarts)\n\n1 warning, 1 info identified, use 'oc status --suggest' to see details.<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Let&#8217;s ignore the warning right now and take a look at the output from the pod.<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc logs deployment\/wordpress-frontend\nNo 'wp-config.php' found in \/var\/www\/html, but 'WORDPRESS_...' variables supplied; copying 'wp-config-docker.php' (WORDPRESS_DB_HOST WORDPRESS_DB_MARIADB_PORT (...)\nWORDPRESS_FRONTEND_SERVICE_PORT_80_TCP)\nAH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.129.1.170. Set the 'ServerName' directive globally to suppress this message\nAH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.129.1.170. Set the 'ServerName' directive globally to suppress this message\n&#91;Thu May 18 10:51:30.465311 2023] &#91;mpm_prefork:notice] &#91;pid 1] AH00163: Apache\/2.4.56 (Debian) PHP\/8.2.6 configured -- resuming normal operations\n&#91;Thu May 18 10:51:30.465362 2023] &#91;core:notice] &#91;pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'<\/code><\/pre>\n\n\n\n<p>It looks much better. No more errors related to attempt to bind to port 80\/tcp.<\/p>\n\n\n\n<div style=\"height:14px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Adding persistent shared storage volume<\/h3>\n\n\n\n<p>Out of the box the deployment is configured to use an ephemeral <em>EmptyDir<\/em> volume for \/var\/www\/html. You can confirm it by running the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc describe deployment wordpress\n(...)\n    Mounts:\n      \/var\/www\/html from wordpress-volume-1 (rw)\n  Volumes:\n   wordpress-volume-1:\n    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)\n(...)<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Since we have OpenShift Data Foundation installed we can utilise it in order to provide persistent and shared storage across multiple instances of wordpress frontend container:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc set volume deployment\/wordpress-frontend --add --name wordpress-volume-1 -m \/var\/www\/html -t pvc --claim-size 1Gi --claim-class ocs-storagecluster-cephfs --claim-mode ReadWriteMany --overwrite\ndeployment.apps\/wordpress-frontend volume updated<\/code><\/pre>\n\n\n\n<p>Just to confirm it has been configured as expected I again run <code>oc describe deployment<\/code> command:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc describe deployment wordpress\n(...)\n    Mounts:\n      \/var\/www\/html from wordpress-volume-1 (rw)\n  Volumes:\n   wordpress-volume-1:\n    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)\n    ClaimName:  pvc-ztrk6\n    ReadOnly:   false\n(...)<\/code><\/pre>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Accessing running WordPress instance<\/h3>\n\n\n\n<p>In order to access the application from outside the cluster, I need to expose it to the external world by creating a route and pointing it to the right service port. Therefore I run the following command to get route with SSL termination provided by the OpenShift:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>$ oc create route edge --service=wordpress-frontend --port=8080-tcp --hostname=wordpress.apps.ocp4.example.com\nroute.route.openshift.io\/wordpress-frontend created<\/code><\/pre>\n\n\n\n<p>The app should be available now via https:\/\/wordpress.apps.ocp4.example.com<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2046\" height=\"1684\" src=\"https:\/\/blog.openshift.one\/wp-content\/uploads\/2023\/05\/Screenshot-2023-05-18-at-13.13.10.png\" alt=\"\" class=\"wp-image-105\" srcset=\"https:\/\/blog.openshift.one\/wp-content\/uploads\/2023\/05\/Screenshot-2023-05-18-at-13.13.10.png 2046w, https:\/\/blog.openshift.one\/wp-content\/uploads\/2023\/05\/Screenshot-2023-05-18-at-13.13.10-300x247.png 300w, https:\/\/blog.openshift.one\/wp-content\/uploads\/2023\/05\/Screenshot-2023-05-18-at-13.13.10-1024x843.png 1024w, https:\/\/blog.openshift.one\/wp-content\/uploads\/2023\/05\/Screenshot-2023-05-18-at-13.13.10-768x632.png 768w, https:\/\/blog.openshift.one\/wp-content\/uploads\/2023\/05\/Screenshot-2023-05-18-at-13.13.10-1536x1264.png 1536w\" sizes=\"auto, (max-width: 2046px) 100vw, 2046px\" \/><\/figure>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Scaling wordpress frontend containers<\/h3>\n\n\n\n<p>In order to scale out wordpress-frontend pods you can simply run:<\/p>\n\n\n\n<pre class=\"wp-block-code has-tertiary-color has-foreground-background-color has-text-color has-background\" style=\"font-size:14px\"><code>oc scale deployment wordpress-frontend --replicas=3\ndeployment.apps\/wordpress-frontend scaled\n$ oc get pods\nNAME                                READY   STATUS    RESTARTS       AGE\nvirt-launcher-wordpress-db-75b8w    1\/1     Running   0              25h\nwordpress-frontend-cd5595d4-gbzmf   1\/1     Running   1 (107s ago)   109s\nwordpress-frontend-cd5595d4-smcsg   1\/1     Running   1 (2m ago)     2m3s\nwordpress-frontend-cd5595d4-zqzd2   1\/1     Running   1 (106s ago)   109s<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">TODO<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Provide MariaDB configuration parameters through Secret instead of deployment variables<\/li>\n\n\n\n<li>Configure Liveness and Readiness checks<\/li>\n\n\n\n<li>Configure Network Policies<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>The purpose of this exercise is to demonstrate how containers and virtual machines can work together. Additionally I also demonstrate a bit of security topic in the container world. I will create a simple service which include: To make the exercise more interesting I decided that every single step will be done in CLI. In [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,8],"tags":[12,9,11,14],"class_list":["post-93","post","type-post","status-publish","format-standard","hentry","category-openshift","category-virtualization","tag-linux","tag-openshift","tag-virtualization","tag-wordpress"],"_links":{"self":[{"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/posts\/93","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/comments?post=93"}],"version-history":[{"count":24,"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/posts\/93\/revisions"}],"predecessor-version":[{"id":122,"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/posts\/93\/revisions\/122"}],"wp:attachment":[{"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/media?parent=93"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/categories?post=93"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.openshift.one\/index.php\/wp-json\/wp\/v2\/tags?post=93"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}