— Tutorial, OpenShift, Containers, Kubernetes, K8s — 12 min read
Build application from the GitHub $ oc new-app --as-deployment-config [github link]
Repo contains Dockerfile, so use that instead of S2I $ oc new-app [github link] --as-deployment-config --strategy docker
Registry that contains docker image $ oc new-app -as-deployment-config --docker-image= [registry link]
Weird cases, what if repo contains dockerfile as well as index.php? OCP cannot decide in that case, you have to help
oc-new app flags
image stream flag in detail: instead of public nginx, use rhel nginx in the image stream for example or directly deploy the image stream
strategy flag in detail
shortcuts for flags that will result in the same outcome $ oc new-app --as-deployment-config [FLAGS] *FLAGS COULD BE:
oc new-app creates a BuildConfig, ImageStream, Deployment (DeploymentConfiguration with the flag), and a Service, you need to expose the service to create route
How to import docker images to image stream $ oc import-image [imagename] --configm --from [registry link] --insecure
oc new-app for subfolder of github, use --context-dir for the folder selection
how to rebuild an app, that doesn't have auto build trigger? $ oc start-build [buildconfig name]
open remote shell in a container in the pod alpha $ oc rsh alpha
open a remote shell in pod alfa and run ls command $ oc rsh alpha ls
copy file into a running container, container must contain tar $ oc cp
edit a resource (oc get ... -o yaml + oc apply combo ) $ oc edit
1$ oc new-app --as-deployment-config <git>#<folder> --context-dir <branchname>2# if you do not have a dockerfile a suitable s2i will be used, unless you tell one from your imageStream, if you have dockerfile it will use it by default no need to define strategy in this case 3$ oc new-app --as-deployment-config --docker-image=registry.access.redhat.com/imagename 4$ oc new-app --as-deployment-config --image-stream=<equivalent-to-S2I-image> --strategy=<source/docker/pipeline> --code=<github.repo> OR --docker-image=<image-repo> 5$ oc new-app --as-deployment-config -l key=value --name value ENV_VAR_KEY=ENV_VAR_VALUE[NOFLAG]6$ oc import-image imagename --config --from registry.link.here --insecure #this will import image to OCP registry7$ oc logs bc/name #get the logs from the latest build 8$ oc logs build/my-app-2 # get the logs from the second build, from the same build config 9# oc logs myapp-build-2 # get the logs from a pod used to build the app second time 10$ oc status #to see new-app results11$ oc start-build bc_name #starts rebuilding the application, so if you don't have triggers set up, you can manually re-run builds 12$ oc get templates -n openshift # careful, you need openshift namespace, that's where the default templates are13# when troubleshooting, first curl the endpoint see if it is working 14# then check if pods can see the endpoints: 15$ oc get ep # get endpoints 16$ oc describe pod <podname> | grep IP # the ip should match service endpoint 17# if you are connecting to the db, ensure that credentials are correct 18# then check if one pod can see the other pod, normally you can go into a pod and ping it but if you don't have it, use curl so 19$ oc rsh [podname] bash -c 'echo >/dev/tc/$OTHER_SERVICE_NAME/PORT# && echo OK || echo FAIL'20# When executing a command on a /dev/tcp/$host/$port pseudo-device file, Bash opens a TCP connection to the associated socket. 21# if you need to copy a configuration/sql table etc to the pod you can just copy it 22$ oc cp ~/path/to/file.txt pod-name:/path/to/file.txt #note if it is a file, destination is a file, if it is a folder, destination is a folder
Aim: select a containerization method and package it to run on OCP
1RUN yum --disablerepo=* --enablerepo="rhel-7-server-rpms"2RUN yum update3RUN yum install -y httpd4RUN yum clean all -y
into
1RUN yum --disablerepo=* --enablerepo="rhel-7-server-rpms" && \2RUN yum update && \3RUN yum install -y httpd && \4RUN yum clean all -y
LABEL instructions distinguish Openshift from Kubernetes by adding io.openshift
to your labels
common labels, io.openshift.tags, io.k8s.description io.openshift.expose-services
io.openshift.expose-services: PORT[/PROTOCOL]:NAME 8080/tcp:my-deployment; this label contains list of svc ports that match the EXPOSE instructions in the Dockerfile
Dockerfile best practices for ENV and LABEL: single equal and \ separated
ENV MYSQL_DATABASE_USER="my_db_usr" \ MYSQL_DATABASE="mydb"
LABEL version="2.0" \ description="This is my db image"\ creationDate="
USER: that is an important concept. Red Hat recommends running the container as non-root. But OCP does not honour the USER on Dockerfile; it uses a random UID that is not 0 (root)
Building images with ONBUILD instruction. Use ONBUILD on parent container image. So when child refers to parent image via FROM, building the child image will trigger ONBUILD commands for the child container.
Why not just go ahead and use those commands in the child? For ease of consistency. The architect can create set of rules on the parent container, and devs can refer to the parent image instead.
Podman and Buildah does not use ONBUILD as it is not part of OCI spec.
When you write a Dockerfile that builds an image to run on OCP, you need to address:
so add the following to the dockerfile to deal with the first two
1RUN chgrp -R 0 [directory/here] && chmod -R g=u [directory/here]
By default OpenShift Container Platform runs containers using arbitrary User IDs. So the container user does not have Root USER priviliges
Note that Root User is different from Root Group. Root group does not have priviliged rights, it is only root User that has.
So for an image to support running as an arbitrary user, it must be part of Root Group.
How to change the port to run above 1024 on Dockerfile
1EXPOSE 8080
1# On child dockerfile, i.e. httpd on port 802RUN sed -i "s/Listen 80/Listen 8080/g" /etc/httpd/conf/httpd.conf
1# Dont use a name, user number 2USER 1001
'{"spec":{"template":{"spec":{"serviceAccountName": "myserviceaccount"}}}}'
Given the following Dockerfile:
1FROM registry.access.redhat.com/ubi8/ubi:8.0 23MAINTAINER Red Hat Training <training@redhat.com>45# DocumentRoot for Apache6ENV DOCROOT=/var/www/html 78RUN yum install -y --no-docs --disableplugin=subscription-manager httpd && \ 9 yum clean all --disableplugin=subscription-manager -y && \10 echo "Hello from the httpd-parent container!" > ${DOCROOT}/index.html1112# Allows child images to inject their own content into DocumentRoot13ONBUILD COPY src/ ${DOCROOT}/ 1415EXPOSE 801617# This stuff is needed to ensure a clean start18RUN rm -rf /run/httpd && mkdir /run/httpd1920# Run as the root user21USER root 2223# Launch httpd24CMD /usr/sbin/httpd -DFOREGROUND
Probably in the exam they would give me a parent container that will have a pre-built parent Dockerfile Probably the parent file will contain USER Root, won't be able to access system files because I haven't changed the owner, running on ports < 1024 Possibly may ask me to improve the build efficiency, by combining all RUN commands that are consecutive, as one
Commands I should know for EX288:
EXPOSE 8080
or ports > 1024Typically developers can inject data into container via configuration file, environment variable or on the fly via command line. This section covers them all. Secrets have various types, service-account-token, basic-auth, ssh-auth, tls, opaque. Opaque does not perform any validation, and accepts any key/value pair If you mount secret as a volume, they are backed by temporary file storage facilities (tmpfs) and never stored on a node Secrets are namespace scoped
How to create configmap from literals $ oc create configmap config_map_name --from-literal key1=value1 --fron-literal key2=value2
How to create secret ? $ oc create secret generic secret_name --from-literal username=user1 --from-literal password=password1
How to create configmap from a file $ oc create configmap config_map_name --from-file /home/file.txt
Where file name is the key and values inside the file.txt is the value
ConfigMap can be shortened as cm
How to create a secret from file ? $ oc create secret generic my_secret --from-file /home/secret.txt
How to edit secret YAML instead of base64 encoding for the passwords/usernames Use 'stringValue' instead of 'data' for JSON key. See Below for the full example
1apiVersion: v1 2stringValue: #instead of data 3 username: user14 password: pass15kind: Secret6metadata:7 name: my_secret8 type: Opaque
oc set env
$ oc set env dc/mydcname --from configmap/myconfig
$ oc set env dc/mydcname --from secret/mysecret
$ oc set volume dc/mydcname --add -t configmap -m /var/path --name myvol --configmap-name myconf
a lot to unpack, --add is for addition, -t is for type, -m mount path --name is volume name, --configmap-name is obvious
to inject secret as volume
$ oc set volume dc/mydcname --add -t secret -m /var/path --name myvol --secret-name mysecret
$ oc set triggers dc/mydcname --from-config --remove
$ oc set triggers dc/mydcname --from-config
$ oc rollout latest mydcname
Commands I should know for EX288:
$ oc create secret generic --help
has the cheat sheet you may need$ oc create secret generic --from-literal key1=value1
$ oc create secret generic --from-file=/path/to/file
filenames in the folder become the key$ oc set volume dc/myapp --add -t secret -m /path/to/folder 1--name myapp-volume --secret-name appsecret
Goal: Interact with an enterprise registry Manage container images in registries (internal/external). Acccess OCP registry. Create ImageStream for images in external registries.
Aim:
Commands I should know for EX288:
$ podman login quay.io
$ skopeo inspect --creds username:passord docker://registry.redhat.io/...
$ read -p "PASSWORD" -s hiddenpassword && skopeo inspect --creds username:$hiddenpassword ...
$ skopeo copy --dest-tls-verify=false containers-storage: myimage docker://registry.example.com/...
$ skopeo copy --dest-tls-verify=false oci:/home/myimage/folder docker://registry.example.com/...
$ skopeo delete docker://registry.example.com
$ oc create secret docker-registry myregistrycreds --docker-server myserverurl --docker-username myuser --docker-password mypassword
$ oc create secret generic myregistrycreds --from-file .dockerconfigjson=${XDG_RUNTIME_DIR}/containers/auth.json --type kubernetes.io/dockerconfigjson
$ oc secrets link default myregistrycreds --for pull
$ oc secrets link builder myregistrycreds
$ oc create new-app --as-deployment-config --name sleep --docker-image quay.io/username/image:1.0
Let's begin:
Login to quay.io where we will store the image podman
copy the oci image to quayio with skopeo
inspect the image if you want or search for it or run it locally to ensure that it is running
how to pass password to the shell/terminal without showing in history?
Deploy the image to OpenShift
If you try to deploy the image from an external registry it will fail
Create a secret
Link the secret
Now create the application
Aim:
Access the OCP Internal Registry with Linux container tools (docker/podman)
You need admin rights to expose the internal container registry
OpenShift Image Registry Operator manages the registry and settings are in the cluster config in openshift-image-registry namespace
To expose the registry
Get the route
login to docker / podman with ocp
inspect with skopeo after podman/docker login
copy image to ocp registry
list image streams
get the is tag
import from another registry
to update the image stream with the latest from the registry $ $ oc import-image myis[:tag] --confirm
to create image streams from other repos you need pull secrets
Commands I should know for EX288:
$ oc create secret generic --help
has the cheat sheet you may need$ oc create secret generic --from-literal key1=value1
$ oc create secret generic --from-file=/path/to/file
filenames in the folder become the key$ oc set volume dc/myapp --add -t secret -m /path/to/folder 1--name myapp-volume --secret-name appsecret
Pipeline build creates a new Jenkins server, subsequent builds share the same jenkins server
Docker requires dockerfile, runs on buildah base img in a pod
Custom is custom
Build Config Sets triggers when the image should be rebuilt
you got 2 options
if the parent img changes, img change trigger
use webhook to trigger new builds once the code is changed
to add trigger to a build config use set triggers
to trigger if the parent img changes
to stop trigger just add --delete flag to the end from the trigger
for webhook trigger you MUST define a SECRET, with a KEY: 'WebHookSecretKey'
oc new-app creates git and generic secrets to use, just take the secrets and add to your VCS
if you want github/gitlab or bitbucket you can just add --from-...
to build images from source images, such as my custom php 7.0, you need to be able to pull the image and build it
service account builder does that for you, just need to add secret and link to it so the robot has the rights
then import the image
then create the new app, if you import-image to your internal registry with a new base, then it will re trigger build
OCP Template is the Helm Chart for Kubernetes
why use templates? Software Vendor to deploy all at once or multi tier application for testing environment (web/backend/db)
The only difference is: template uses 'objects' instead of 'spec'
In the template you can inject params too and a common label for all objects
also you can inject random default params/values too, see the YAML below
1apiVersion: template.openshift.io/v12kind: Template 3metadata: 4 name: mytemp 5 annotations:6 description: "Descibe here"78objects:9- apiVersion: v110 kind: Pod 11 # does that look familiar?12 spec:13 containers:14 #bla bla 15 name: ${MYPARAM}1617#params to be injected to the objects18parameters: 19 - name: MYPARAM20 value: delta 21 required: true 22 description: "describe the reason here" 2324 - name: APIKEY25 generate: expression 26 from: "[a-zA-Z0-9]{12}"27 description: random string generated by the template at run time 28#labels for the resources 29labels:30 mylabel: myapp
$ oc get templates -n openshift
$ oc process --parameters -n openshift nodejs-mongdb-template
Question for this section could be create a multi container template from existing resources
use the following to export all objects as a template. Very Important!
order is important, secrets first don't wait for them, pvc last because it takes time to bind
To describe OpenShift resouce type use oc explain routes, to get nested level response oc explain routes.spec
oc new-app and oc process uses templates to create Applications from Templates;
to pass parameters to oc new-app add -p flag
to create a template with oc process with params, you need to send to a yaml file first then use oc create to deploy $ oc process -f mytemplate.yaml -p PARAM1=value1 > myresourcelist.yaml $ oc create -f myresourcelist.yaml
or your can just pipe it
To find which params you need to pass to template
OpenShift recommends oc new-app rather than oc process
Potential Exam Questions: Creating MultiContainer
When you try to export multiple items but get an error, you can just add one by one and append to a file
$ oc get -o yaml is --export > /tmp/is.yaml $ cp /tmp/is.yaml /tmp/is-clean.yaml
TODO: COMPLETE THE GUIDED EXERCISE!
1...2livelinessProbe:3 httpGet:4 path: /health5 port: 8080 6 initialDelaySeconds: 107 timeoutSeconds: 1
1* When to use HTTP Check: When you have a REST API and apps that can return HTTP Status code 23* Container Exec Check
... livelinessProbe: exec: command:
1- cat 2- /tmp/health
initialDelaySeconds: 10 timeoutSeconds: 1
1* When to run Container Exec Check: When container runs a process or shell script running in the container 23* TCP Socket Check
... livelinessProbe tcpSocket: port: 8080 initialDelaySeconds: 15 timeoutSeconds: 1
1* When to run TCP Socket Check: When you run deamons and open TCP ports: DB Servers, APP Servers, File Servers, Web Servers etc. 234* How to set probes on the UI? open up the YAML and edit 56* How to set probes on the CLI? 7 * $ oc set probe dc/myapp --readiness --get-url=http://:8080/healthz --period=20 8 * $ oc set probe dc/myapp --liveliness --open-tcp=3306 --period=20 --timeout-seconds=19 * $ oc set probe --help to learn more 1011TODO: complete the demo1213## 7.3 Seelct Appropriate Deploy Strategy 1415### Deployment Strategies 1617* A deployment strategy is a method of changing or upgrading an app 1819* Two Deployment Strategies: Deployment Configuration for the deployment strategy and other one is use Router to route to certain pods; 2021 * For Deployment Strategy you can use Rolling or Recrate22 * For Route AB Deployment, Blue-Green, N-1 Compatibility, Graceful Termination 23 * Let's first talk about Deployment Strategies then Router below2425* Deployment Strategies2627* This is the default if you do nothing 2829* It uses readiness probes to see, and it is a canary deployment, deploy one to test, if doesn't work do not deploy 3031* Recrate: When you use PVs with RWO access which does not allow writes from multiple pods, then you should use Recrate, sorry dude 3233* Life-cycle hooks with deployment strategies: 34 * Both deployment strategies work with LC Hooks 35 * Pre/Mid/Post LC hooks are executed during the deployments 36 * Each Hook has failurePolicy that you can run when a hook fails. You can Abort/Retry or Ignore 373839404142## 7.5 Manage App Deploy with CLI 4344# 8. CI/CD Pipelines 4546## 8.3 Implement Jenkins 4748## 8.5 Custom Jenkins Pipeline 4950# 9. Building Apps for Openshift 5152## 9.1 Integrating External Services 5354## 9.3 Containerize Svc 5556## 9.5 Deploy Apps with OCP Runtimes 5758# End59606162export const _frontmatter = {"title":"DO288 Red Hat OpenShift Development II Containerizing Applications","date":"2021-01-15T00:00:00.000Z","description":"Summary notes for my Red Hat Certified Specialist in OpenShift Application Development EX180 Exam","tags":["Tutorial","OpenShift","Containers","Kubernetes","K8s"]}