This demo will take you through a process of building and testing a web application locally. We will be using Docker Desktop Enterprise (DDE)
to scaffold an application, we'll then push the docker image up to a private image registry (signing the image using Docker Content Trust (DCT)
), and automatically scan and promote the repository using Docker Trusted Registry (DTR)
. Once we have completed this phase of the development process we will run the web application Docker Universal Control Plane (UCP)
on a Kubernetes cluster.
(NB we can also use Docker Swarm as the orchestration engine (works great for Windows workloads as well as Linux based workloads).
-
Ensure Docker Desktop Enterprise is installed on your machine. If you are using Docker for Windows or Docker for Mac, you're good to go. If not, you can download DDE from https://hub.docker.com/editions/community/docker-desktop-ent
-
Ensure that you have login credentials for Docker Enterprise Platform 3.0 hosted at https://ucp.west.us.se.dckr.org/
-
Create a
respository
namedcatweb
withinDTR
(https://dtr.west.us.se.dckr.org/) and set-upmirroring
toDockerHub
, apromotion
to a production namespace, and optionally a webhook toSlack
. -
Within a
terminal
set your env variable forDTR
and login toDTR
$ export DTR=dtr.eu.demo.mirantis.com
$ echo $DTR
$ docker login $DTR -u <uname> -p <password>
- Optional - Enable and disable content trust per-shell or per-invocation
In a shell, you can enable content trust by setting the DOCKER_CONTENT_TRUST environment variable. Enabling per-shell is useful because you can have one shell configured for trusted operations and another terminal shell for untrusted operations. You can also add this declaration to your shell profile to have it turned on always by default.
To enable docker content trust
in a bash shell enter the following commands to set the env var and view it
$ export DOCKER_CONTENT_TRUST=1
$ echo $DOCKER_CONTENT_TRUST
1
- Install
Visual Studio Code
from https://code.visualstudio.com/download
There are two parts to the demo. The first part will take you through the process of quickly creating a net new cloud native application in a matter of seconds. The process takes you through scaffolding an application based on the Cloud Native Application Bundle (CNAB)
specification using Docker Application Designer within Docker Desktop Enterprise
. The second part will go through the process of using GitHub, DDE, DTR, and UCP.
This demo is designed to show a build, share, run Docker workflow using a simple Flask-based web app, catweb
.
The basic flow is to initially build and run the app locally using Docker Desktop Enterprise, modify the web template to show how hot mounting a volume works, pushing the image to Docker Trusted Registry
optionally signing the image with Docker Trusted Registry
, then deploying onto AWS
using Docker Universal Control Plane
.
- Click the
Moby
icon in your system tray and navigate around the interesting options, explaining each one in turn. - Click
Design new application...
,Custom application
and explain the different availableservices
and associatedports
etc. - Click the back icon
<
and then selectChoose a template
- Click
Flask / NGINX / MySQL application
, leave the ports as default and clickContinue
- Click a name
demoApp
and selectScaffold
- Click
Show logs
and describe the process that DDE is going through - Click
Hide logs
(optional),Run application
, view the application by opening a web browser and entering http://localhost - Click
Open in Visual Studio Code
and describe the folder and file structure, and the docker files that were generated - Run
docker ps
in a terminal to view the running container
We have not had to learn how to create our Dockerfile(s), docker-compose.yaml, or create the folder and file structure, a bonus being that we have a skeleton application which is up and running in less than a minute.
Now that we have our scaffolded (skeleton) Flash / NGINX / MySQL Server application, we can build upon this and create our net new cloud native application for our project
- Within the Application Designer UI click
Stop
to stop the application, then click the back<
chevron - Click the
delete
icon,confirm and remove application
, and exitx
the Application Designer UI
- Open a terminal window and change directory to where you want to clone the
catweb
sampleGitHub
repo too.
$ cd ~/Documents/Docker/Demonstrations
$ git clone https://github.com/jas-atwal/catweb.git
Cloning into 'catweb'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 291 (delta 2), reused 0 (delta 0), pack-reused 285
Receiving objects: 100% (291/291), 59.90 KiB | 285.00 KiB/s, done.
Resolving deltas: 100% (161/161), done.
List the files within the directory
$ cd catweb
$ ls
COMMANDS.md README.md catweb-deployment.yaml expose-service.yaml src
Dockerfile app.py docker-compose.yml requirements.txt templates
Notice that we have a
Dockerfile
and adocker-compose.yaml
file
-
Within
VS Code
open thecatweb
folder, then open theDockerfile
and explain the how the app isbuilt
. You can also show the source code if you wish -
Build
the app (explain that Docker is going through each step within the Dockerfile in the specified order), and use thedocker image
command to view the details of the built image
$ docker build --no-cache -t catweb .
Successfully built fd80b366dad9
Successfully tagged catweb:latest
Tagging alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb as alpine:latest
Let's view the generated image
$ docker image ls | grep catweb
catweb latest fd80b366dad9 2 minutes ago 74.1MB
- Now that the image has been built, we can run the image as a container using
docker-compose
. Open thedocker-compose.yaml
file withinVS Code
and describe the contents. Now let'srun
the app onDocker Swarm
as theorchestration engine
using the commands contained within thedocker-compose
file.
$ docker-compose up
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Creating catweb_web_1 ... done
Attaching to catweb_web_1
web_1 | * Serving Flask app "app" (lazy loading)
web_1 | * Environment: development
web_1 | * Debug mode: on
web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1 | * Restarting with stat
web_1 | * Debugger is active!
web_1 | * Debugger PIN: 316-525-960
Open a second terminal
and view the running container using
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7c9ba2ff21b2 catweb_web "python3 /usr/src/ap…" About a minute ago Up About a minute 0.0.0.0:5000->5000/tcp catweb_web_1
-
Open a web browser and show the app running at http://localhost:5000
-
Open the
templates/index.html
file withinVS Code
and update thehtml
tag<h4>Catweb - Curated Cat Gifs!</h4>
by adding your name
<h4>Catweb - Jas' Curated Cat Gifs!</h4>
-
Refresh
the web page at http://localhost:5000 and notice the change. -
Stop the container using
CTRL+C
^CGracefully stopping... (press Ctrl+C again to force)
Stopping catweb_web_1 ... done
- Let's test the running of the app within multiple containers (three in our case) using
docker stack deploy
, anddocker swarm
for orchestration. We can check the running containers usingdocker ps
ordocker container ls
Note We can also run the containers locally using Kubernetes as the orchestrator
$ docker stack deploy -c docker-compose-prod.yml catweb
Creating network catweb_default
Creating service catweb_web
-
Let's view the app at http://localhost:5000. Refresh the browser and notice the
Container ID
changes occasionally. This is because we are running three instances of the application in three separate networked containers and the traffic is being load balanced between them. -
View the three running containers
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
438d7ec74910 catweb:latest "python3 /usr/src/ap…" 4 minutes ago Up 4 minutes 5000/tcp catweb_web.1.5bqnigtauc6ewd1jrts10lm7v
a6d46717c3e1 catweb:latest "python3 /usr/src/ap…" 4 minutes ago Up 4 minutes 5000/tcp catweb_web.2.uvcfnuaxsyg0wffosupokrt5q
17665d8af3c3 catweb:latest "python3 /usr/src/ap…" 4 minutes ago Up 4 minutes 5000/tcp catweb_web.3.azc8ed275lfeyzwfd1xap38rd
- Let's bring one of the containers identified in step 11 down and then check to see their
STATUS
$ docker container kill 438d7ec74910
438d7ec74910
- Let's check the running containers
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8610e3297c89 catweb:latest "python3 /usr/src/ap…" 8 seconds ago Up 4 seconds 5000/tcp catweb_web.1.p9o12hs072rbzfy27cjm10ocr
a6d46717c3e1 catweb:latest "python3 /usr/src/ap…" 5 minutes ago Up 5 minutes 5000/tcp catweb_web.2.uvcfnuaxsyg0wffosupokrt5q
17665d8af3c3 catweb:latest "python3 /usr/src/ap…" 5 minutes ago Up 5 minutes 5000/tcp catweb_web.3.azc8ed275lfeyzwfd1xap38rd
Notice how a new container has been stood up in place of the container that we killed and has only been up a few seconds
We are now ready to share the image using Docker Trusted Registry
, during which we will also sign
and scan
the image for vulnerabilities
.
Now that the docker image has been built and we have successfully tested the running of the catweb
application locally, we can push the image up to Docker Trusted Registry
so that we can sign, scan, and promote the image from dev
through to production
for final deployment.
- We need to
tag
the image and thenpush
this tagged image to our private registry(DTR)
ensuring that you use your own namespace (replace se-jasatwal with your namespace)
$ docker tag catweb:latest $DTR/se-jasatwal/catweb:latest
$ docker image ls | grep catweb
catweb_web latest cc5142167446 51 minutes ago 74.1MB
catweb latest ebbdcec5a92d About an hour ago 74.1MB
dtr.west.us.se.dckr.org/se-jasatwal/catweb latest ebbdcec5a92d About an hour ago 74.1MB
$ docker push $DTR/se-jasatwal/catweb:latest
The push refers to repository [dtr.west.us.se.dckr.org/se-jasatwal/catweb]
aa9ff091b287: Pushed
164e79b62389: Pushed
2f6e52a272df: Pushed
8d4536d51aeb: Pushed
13806d62f1e3: Pushed
226cecc8e243: Pushed
03901b4a2ea8: Layer already exists
latest: digest: sha256:2d9db17f7849327fe7c53e5e90e3b9c7398820acd189bc24a97536f59742f3c3 size: 1783
Signing and pushing trust metadata
Enter passphrase for repository key with ID 7d9b31d:
Successfully signed dtr.west.us.se.dckr.org/se-jasatwal/catweb:latest
The
DTR
which we are using for this demo isdtr.west.us.se.dckr.org
If you have enabled
DOCKER_CONTENT_TRUST=1
as anenvironment variable
then the first time youpush
an image usingcontent trust
on your system, the session looks like this:
Signing and pushing trust metadata
You are about to create a new root signing key passphrase. This passphrase
will be used to protect the most sensitive key in your signing system. Please
choose a long, complex passphrase and be careful to keep the password and the
key file itself secure and backed up. It is highly recommended that you use a
password manager to generate the passphrase and keep it safe. There will be no
way to recover this key. You can find the key in your config directory.
Enter passphrase for new root key with ID fa0e171:
Enter a passphrase when prompted.
Make note of this
passphrase
as it is not retrievable if forgotten.
Once complete you will receive a response similar to that below
Finished initializing "dtr.west.us.se.dckr.org/se-jasatwal/catweb"
Successfully signed dtr.west.us.se.dckr.org/se-jasatwal/catweb:latest
- In a web browser navigate to https://dtr.west.us.se.dckr.org/. When prompted to log in, please do so
Click on Repositories
and within the Filter by: All Namespaces
enter your namespace
name, select the catweb
repositories and select the tag
first to show the image that you just uploaded. Then discuss the automation of:
image signing
image scanning,
image mirroring
image promotions and
webhooks
Now that the image has been pushed to our private registry, has been signed, scanned, and promoted through to our production namespace, let's run the web application within a container on Kubernetes
via Docker Universal Control Plane UCP
.
We can run the container using a
Kubernetes yaml
file or alternatively via thecommand line
. We will use the latter!
- Create a
Kubernetes deployment
using theimage
that you pushed up toDTR
and check it exists
$ kubectl create deployment catweb --image=$DTR/se-jasatwal/catweb
deployment.apps/catweb created
$ kubectl get deploy | grep catweb
catweb 1/1 1 1 30s
Where
se-jasatwal
is your namespace inDTR
. If you have not set theDTR environment variable
please substitute$DTR
withdtr.west.us.se.dckr.org
- Create a
Kubernetes service
exposingport 5000
and using typeLoadBalancer
$ kubectl expose deployment catweb --port=5000 --type=LoadBalancer
service/catweb exposed
- Check to see if the container is running
$ kubectl get pod | grep catweb
catweb-5c6d4b9c95-z8f4f 1/1 Running 0 5m49s
- Bring back the details of the service so that you can copy the
EXTERNAL IP
address which you will need in the next step
$ kubectl get svc
$ kubectl get svc | grep catweb
catweb LoadBalancer 10.96.33.124 a3c5da531eb2111e9a6fb0242ac11000-757615726.us-west-2.elb.amazonaws.com 5000:35435/TCP 3h27m
If the EXTERNAL_IP is showing as pending, please wait a few seconds and run the
kubectl get svc | grep catweb
command again until it returns a string as above.
- In a web browser navigate to http://<external_ip>:5000. View your newly deployed production application running on a
Kubernetes cluster
onAWS
via theDocker Enterprise Platform
.
NOTE: the external_ip address in the example above is a3c5da531eb2111e9a6fb0242ac11000-757615726.us-west-2.elb.amazonaws.com
- Show
UCP Dashboard
and navigate around the aspects such asAccess Control
,Kubernetes Services
andPods
etc.
- Let's scale the application to provide high availability. Replicas can be specificed within the Kubernetes yaml file, however you can also do this via the command line interface. Let's increase the number of running containers hosting an instance of the application to five.
$ kubectl scale --replicas=5 deployment/catweb
deployment.extensions/catweb scaled
- Now let's describe the deployment to view how many ReplicaSets we have, we are expecting five
(5/5 replicas created)
$ kubectl describe deployment catweb
Name: catweb
Namespace: se-jasatwal
CreationTimestamp: Mon, 14 Oct 2019 12:50:41 +0100
Labels: app=catweb
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=catweb
Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=catweb
Containers:
catweb:
Image: dtr.west.us.se.dckr.org/se-jasatwal/catweb
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Progressing True NewReplicaSetAvailable
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: catweb-5c6d4b9c95 (5/5 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 5m25s deployment-controller Scaled up replica set catweb-5c6d4b9c95 to 5
Review the
Events
section towards the bottom of the output. We have successfully scaled out to five ReplicaSets.
You have successfully containerised an application, tested it locally, pushed it up to a private registry, signed, scanned, and promoted the image, then deployed the application to Kubernetes. All using the Docker Enterprise Platform - the only end-to-end secure software supply chain from DEV to PROD! 😁
Note: Do this after EACH demo
- Manually delete running swarm container from UCP
- Manually delete tagged catweb:latest image from DTR
- Remove all images and containers
$ docker image ls | grep catweb
$ docker image rm dtr.west.us.se.dckr.org/se-jasatwal/catweb
$ docker image rm catweb
$ docker ps -a
7c9ba2ff21b2
$ docker container rm 7c9ba2ff21b2
$ kubectl delete deploy catweb
$ kubectl delete svc catweb
$ kubectl get pods
catweb-5c6d4b9c95-z8f4f
$ kubectl delete pod catweb-5c6d4b9c95-z8f4f
$ docker image prune -a
$ cd ..
$ rm -R ~$PWD/catweb/
- Remove the
demoApp
application
$ rm -R ~/Documents/Docker/Demonstrations/app-designer/demoApp
Note: The location of your Application Designer
application files will differ from that above
-
In a web browser navigate to https://ucp.west.us.se.dckr.org/. If prompted to log in, please do so
-
From the left menu, click
Swarm
, thenServices
-
Click the
Create
button and fill in the following values replacingse-jasatwal
with yournamespace
- Image name:
dtr.west.us.se.dckr.org/se-jasatwal/catweb:latest
- Under
Network
selectAdd Port+
- Enter the port numbers
5000
, and5000
in thesource
andtarget
fields respectively - Under
Labels
add two lables:interlock.hostname
andwww
interlock.domain
andcatweb.demo
Note: Make sure to click the plus after each one
-
Click
Create
-
After the container is successfully deployed, navigate in the web browser to http://www.catweb.demo. This will navigate to your newly deployed container running on AWS via Docker Enterprise Platform.
Congratulations!! 🎉