Optimize a ContainerFile File

Mindwatering Incorporated

Author: Tripp W Black

Created: 07/28 at 06:05 PM

 

Category:
RH OpenShift
Reference

Task:


Need to optimize a Containerfile (Dockerfile) file so least amount of command layers (layer = sequences/list of commands) to prep for this Containerfile (Dockerfile) to be a parent to be used with child deployments.

Tasks:
- Reduce LABEL calls to 1 call
- Reduce RUN calls as close to 1 as possible
- Create an image of the parent Containerfile to be used as source to generate child images with default content from /src.

Child Deployment Tasks:
- Create child derivative version of Dockerfile
- Create deployment using the new Dockerfile


Lab Environment:
Git Repo: git.ocp4.mindwatering.net/mwapp/dockerbuild.git
Branch: dev
Username: developer
Password: mydevpassword

Workstation: mydev1.mindwatering.net
Username and Password: <same as repo>
Workstation Working Directory: ~/dockerbuild/

OCP4/OKD: <your OKD on port 6443>
Username and password: <same as repo>
Project: mwapp


Steps:


1. Create working directory (if not exists) and clone:
a. Create working folder:
$ ssh developer@mydev1.mindwatering.net
<enter pwd>
$ cd ~/
$ mkdir mwapp
$ cd mwapp
$ pwd
/home/developer/mwapp

b. Clone the repo:
Note:
- For repo requiring authentication with keys, append " login" or append username, like: git clone http ... developer@git.ocp4.mindwatering.net/mwapp/dockerbuild.git
- Alternately, setup private/public keys if an internal repo.

$ git clone https://git.ocp4.mindwatering.net/mwapp/dockerbuild.git login
<enter username/password prompts>

c. Enter inside repo:
$ ls
dockerbuild

$ cd dockerbuild

d. Switch to correct dev branch:
Note:
- Process: git clone --> git fetch origin --> git switch --> git pull (if someone else might be working while doing all this)
- Use git checkout before git version 2.23.0
- Use git switch starting with git version 2.23.0

$ git fetch origin
<outputs the branches e.g. master, staging, dev, etc.>

$ git switch dev
<confirm switched>

$ git pull
<confirm any updates>


2. Locate the Dockerfile, analyze, and update:
a. View Dockerfile and check for changes needed:
$ ls
...
Dockerfile
...
README.md

$ cp Dockerfile zBackupDockerfile

$ cat Dockerfile

FROM registry.mindwatering.net/ubi9/ubi-minimal:latest

LABEL version="1.0"
LABEL description = "UBI Minimal with Python3 installed"
LABEL owner = "MW IT"
LABEL maintainer = "Tripp Black"

user root

RUN microdnf install -y python3
RUN microdnf clean all
RUN mkdir -p /app
RUN echo "Hello container world - Version 1.0" > /app/index.html

ENV DOCROOT=/app

EXPOSE 8080

USER 1001

WORKDIR /app

CMD [python3", "-m", "http-server", "8080"]


b. Update Dockerfile:
Notes:
- Need to update the LABELs so in one pass
- Need to update the RUNs so in one pass
- Need to add an ONBUILD COPY of src/ from the /app folder so that child based builds on parent image can be performed
- Besides ONBUILD COPY, we can include specific ONBUILD RUN commands to install different additional software for each child image build

$ vi Dockerfile

FROM registry.mindwatering.net/ubi9/ubi-minimal:latest

LABEL version="1.0" \
  description = "UBI Minimal with Python3 installed" \
  owner = "MW IT" \
  maintainer = "Tripp Black"

user root

RUN microdnf install -y python3 && \
  microdnf clean all && \
  mkdir -p /app && \
  echo "Hello container world - Version 1.0" > /app/index.html

ENV DOCROOT=/app

ONBUILD COPY src/ $(DOCROOT)

EXPOSE 8080

USER 1001

WORKDIR /app

CMD [python3", "-m", "http-server", "8080"]

<esc> :wq (to save)


3. Push back up to git (Github):
$ git status
<view that one file has been updated - should be red color because not added to push yet>

$ git add .

$ git status
<view that one file is now green color because added>

$ git commit -m "optimize Dockerfile for child builds and reduce layers"
<confirm message: 1 file changed>

$ git push
<authenticate with username and password>
Username for ...: developer
Password for ...: mydevpassword
<confirm success messge>


4. Verify Containerfile (Dockerfile) with podman:
a. Login:
$ podman login -u developer
<enter password at prompt>
Password: mydevpassword
<verify login says Succeeded>

b. Create an image:
Notes:
- Image name is podman local image from which to create the main app (parent) build and app deploy in OCP/OKD
- Will run from the base folder of the local copy of the repo just pushed (using the single . (dot/period) for this folder

IMPORTANT:
- Podman defaults to the OCI image format which does not support ONBUILD instructions. Use --format docker to switch podman to the docker image format. Otherwise, messages will be presented saying the ONBUILD is being skipped.
- Use the -t flag to specify the name of the parent image "base"
- Use the -f flag or leave out and just specify the filename for the Containerfile (Dockerfile) file/script to use

$ pwd
/home/developer/mwapp/dockerbuild

$ podman build --format docker -t mwappimage-v1 .
<wait for build: blobs --> run of Dockerfile --> LABELS --> USER --> RUN (with package install lines) --> ENV DOCROOT --> ONBUILD COPY (will be ignored - must use docker format) --> EXPOSE --> USER (1001) --> WORKDIR --> CMD (python http run) --> Successfully tagged localhost/mwappimage-v1:latest>

c. Review image and image size:
$ podman images

REPOSITORY				TAG		IMAGE ID		CREATED		SIZE
...
localhost/myappimage-v1		latest		ab12cd34...		12 seconds ago		160 MB
...



5. Deploy mwapp (parent) to OCP/OKD:
a. Create project (namespace) if not created already:
$ oc new-project mwapp
<confirm created>

Verify:
$ oc project
<confirm says Using project 'mwapp'>

b. Create app from the pushed repo's edited Dockerfile:
$ oc new-app --name=mwapp https://git.ocp4.mindwatering.net/mwapp/dockerbuild
<wait, confirm creating resources completed, confirm success message>

- Confirm build progress and that app deploys:
$ oc get po
<view pods confirm build exists for mwapp app>

NAME			READY		STATUS		RESTARTS	AGE
...
mwapp-1-build		0/1		Init:1/2		0		8s
...


$ oc get builds
<confirm running or completed>

NAME			TYPE		FROM		STATUS		STARTED		DURATION
...
mwapp-1		Docker		Git@abc123	Running	12 seconds ago
...


$ oc get bc
<confirm exists>

NAME			TYPE		FROM		LATEST
...
mwapp			Docker		Git		1
...


$ oc get po
<view pods confirm build completed and mwapp app running>

NAME				READY		STATUS		RESTARTS	AGE
...
mwapp-1-build			0/1		Completed	0		45s
mwapp-1234abcd-12ab34	1/1		Running	0		18s
...


c. Expose app:
$ oc expose svc/mwapp
<confirm route exposed>

$ oc get route
<view app routes, and note fqdn route for mwapp>

NAME			HOST/PORT						PATH	SERVICES	PORT		TERMINATION	WILDCARD
...
mwapp			mwapp-container-build.apps.ocp4.mindwatering.net		mwapp		8080-tcp			None
...


d. Confirm app loads in browser:
web browser --> url field: mwapp-container-build.apps.ocp4.mindwatering.net
<confirm web page says: Hello container world - Version 1.0>

e. Confirm parent image:
$ oc get images | grep mwapp
sha256:123...abc image-registry.openshift-image-registry.svc:5000/container-build/mwapp@sha265:123...abc

Notes:
- The parent image is: image-registry.openshift-image-registry.svc:5000/container-build/mwapp
- The parent image is now ready for child deployments.
- The child Dockerfile will need only the FROM line.


6. Deploy a child deployment using the parent's image specifying the /src folder.
Note:
- Typically, the child apps would be either a different git repo/app, or would be a different branch of same repo.
- Use git checkout -b to create a new branch from the current branch dev. Or from any branch add the branch to use as the source at the end - git checkout -b <newbranch> <existingbranch>

a. Confirm still in the git local repo and create the new branch:
$ pwd
/home/developer/mwapp/dockerbuild

$ git checkout -b devchild dev

b. Push the branch to the git (Github) repo:
Note:
- git push -u ensures the created branch on the remote repo is linked to our new branch just created.

$ git push -u origin devchild
<confirm>

c. Update the Containerfile (Dockerfile) for child deployments:
Note:
- Use the image URL from the end of step 5 above.

$ vi Dockerfile

FROM image-registry.openshift-image-registry.svc:5000/container-build/mwapp

<esc> :wq (to save)

d. Create new build in OCP/OKD:
$ oc new-build --name=mwapp-child --strategy=docker --binary=true
<wait>

e. Confirm build:
$ oc get bc
<confirm child exists>

NAME			TYPE		FROM		LATEST
...
mwapp			Docker		Git		1
mwapp-child		Docker		Binary		0
...


f. Build child using the local devchild branch Containerfile:
Note:
- Use --follow to watch the build

$ oc start-build mwapp-child --from-dir=.
<wait>

g. Confirm build:
$ oc get po
<view pods confirm build exists for mwapp app>

NAME				READY		STATUS		RESTARTS	AGE
...
mwapp-1-build			0/1		Completed	0		10m45s
mwapp-1234abcd-12ab34	1/1		Running	0		10m18s
...
mwapp-child-1-build		0/1		Completed	0		60s
...


$ oc get builds
<confirm running or completed>

NAME			TYPE		FROM		STATUS		STARTED		DURATION
...
mwapp-1		Docker		Git@abc123	Completed	8 minutes ago		30s
...
mwapp-child-1		Docker		Binary@def456	Completed	35 seconds ago		15s
...


h. Create a mwapp-child app from the new mwapp-child build:
$ oc new-app mwapp-child --name=mwapp-child
<wait>

i. Confirm running and expose:
$ oc get po
<view pods confirm build completed and mwapp-child app running>

NAME					READY		STATUS		RESTARTS	AGE
...
mwapp-1-build				0/1		Completed	0		11m45s
mwapp-1234abcd-12ab34		1/1		Running	0		11m18s
...
mwapp-child-1-build			0/1		Completed	0		45s
mwapp-child-5678abcd-90ab12	1/1		Running	0		10s
...


j. Expose app:
$ oc expose svc/mwapp-child
<confirm route exposed>

$ oc get route
<view app routes, and note fqdn route for mwapp>

NAME			HOST/PORT							PATH	SERVICES	PORT		TERMINATION	WILDCARD
...
mwapp-child		mwapp-child-container-build.apps.ocp4.mindwatering.net		mwapp		8080-tcp			None
...


k. Confirm output of child's HTML page:
$ cat ./src/index.html
Hello world from child container - Version 1.0

l. Confirm app loads in browser:
web browser --> url field: mwapp-child-container-build.apps.ocp4.mindwatering.net
<confirm web page says: Hello world from child container - Version 1.0>


previous page

×