This document is a walkthrough of the demo presented in this talk.
This demo uses the following software and cloud resources.
- Trivy
- Docker Engine Client 20.10.8
- Docker Engine Server 20.10.8
- a clone of this repository
- Alibaba Container Registry to push container images
- GitHub Actions as CI/CD
Docker
➜ docker version
Client:
Cloud integration: 1.0.17
Version: 20.10.8
API version: 1.41
Go version: go1.16.6
Git commit: 3967b7d
Built: Fri Jul 30 19:55:20 2021
OS/Arch: darwin/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.8
API version: 1.41 (minimum version 1.12)
Go version: go1.16.6
Git commit: 75249d8
Built: Fri Jul 30 19:52:10 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.9
GitCommit: e25210fe30a0a703442421b0f60afac609f950a3
runc:
Version: 1.0.1
GitCommit: v1.0.1-0-g4144b63
docker-init:
Version: 0.19.0
GitCommit: de40ad0
Navigate to the /app
directory. This contains the sample Flask application, a requirements file and the Dockerfile manifest.
Dockerfile
, app.py
, requirements.txt
Login to Alibaba Container Registry: docker login
docker login
Authenticating with existing credentials...
Login Succeeded
While still on the /app
directory invoke the following command in the CLI:
docker build -t hadronp/ubuntu-flask:v0 .
Substitute your DockerHub account name instead of hadronp eg. my_account/ubuntu-flask:v0
docker build -t hadronp/ubuntu-flask:v0 .
Sending build context to Docker daemon 4.096kB
Step 1/6 : FROM python:alpine3.7
alpine3.7: Pulling from library/python
c67f3896b22c: Already exists
8ea0547d7723: Pull complete
711fdf82ca0a: Pull complete
6002973f8486: Pull complete
08ec325072d0: Pull complete
Digest: sha256:8e083aa39117533772c0ecd4327403bb1acf9a9fc7ae14deac6fddeb8c28d2c4
Status: Downloaded newer image for python:alpine3.7
---> b9858a9efe1e
Step 2/6 : COPY . /app
---> bd100e61a5cb
Step 3/6 : WORKDIR /app
---> Running in 2d6e4f6a015b
Removing intermediate container 2d6e4f6a015b
---> 6aeafca5d304
Step 4/6 : RUN pip install -r requirements.txt
---> Running in 02fe15680891
Collecting flask==1.0.2 (from -r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/7f/e7/08578774ed4536d3242b14dacb4696386634607af824ea997202cd0edb4b/Flask-1.0.2-py2.py3-none-any.whl (91kB)
Collecting Werkzeug>=0.14 (from flask==1.0.2->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/20/c4/12e3e56473e52375aa29c4764e70d1b8f3efa6682bef8d0aae04fe335243/Werkzeug-0.14.1-py2.py3-none-any.whl (322kB)
Collecting itsdangerous>=0.24 (from flask==1.0.2->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
Collecting click>=5.1 (from flask==1.0.2->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl (81kB)
Collecting Jinja2>=2.10 (from flask==1.0.2->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB)
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10->flask==1.0.2->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/ac/7e/1b4c2e05809a4414ebce0892fe1e32c14ace86ca7d50c70f00979ca9b3a3/MarkupSafe-1.1.0.tar.gz
Building wheels for collected packages: MarkupSafe
Running setup.py bdist_wheel for MarkupSafe: started
Running setup.py bdist_wheel for MarkupSafe: finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/81/23/64/51895ea52825dc116a55f37043f49be0939bcf603de54e5cde
Successfully built MarkupSafe
Installing collected packages: Werkzeug, itsdangerous, click, MarkupSafe, Jinja2, flask
Successfully installed Jinja2-2.10 MarkupSafe-1.1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-1.1.0
Removing intermediate container 02fe15680891
---> 38ee633f943c
Step 5/6 : EXPOSE 5000
---> Running in d9482c3d9366
Removing intermediate container d9482c3d9366
---> 372d0a4fe4f9
Step 6/6 : CMD python ./app.py
---> Running in eea1d28f06eb
Removing intermediate container eea1d28f06eb
---> c74382bedf20
Successfully built c74382bedf20
Successfully tagged hadronp/alpine-flask:v0
Show the newly built image in the terminal:
docker image ls | grep ubuntu-flask
hadronp/alpine-flask v0 c74382bedf20 2 minutes ago 91.3MB
Push the container image to DockerHub: docker push hadronp/ubuntu-flask:v0
docker push hadronp/ubuntu-flask:v0
The push refers to repository [docker.io/hadronp/ubuntu-flask]
d06a3aaf817a: Pushed
8f83f81506cc: Pushed
9d47dcf94482: Layer already exists
1926d47f169d: Layer already exists
66bd78ef2de1: Layer already exists
55ad70ba131b: Layer already exists
ebf12965380b: Layer already exists
v0: digest: sha256:e6af025f2023fce5834618598162ec1c356753dc234a6fb0f2f1d608038962d8 size: 1786
docker run --detach --publish 5000:5000 hadronp/ubuntu-flask:v0
docker run --detach --publish 5000:5000 hadronp/ubuntu-flask:v0
e3467d02e10d46a59538f7a8e7990f55e1a157b7b5a4a58d27cb54e5c8cf4d9e
Ξ demo/app-code git:(master) ▶ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e3467d02e10d hadronp/ubuntu-flask:v0 "/bin/sh -c 'python …" 27 seconds ago Up 26 seconds 0.0.0.0:5000->5000/tcp compassionate_snyder
On the terminal type the following to view this impossibly awesome app for the first time. curl http://127.0.0.1:5000
Scanner for vulnerabilities in container images, file systems, and Git repositories, as well as for configuration issues
Repository link: https://github.com/aquasecurity/trivy
Installing in Debian/Ubuntu systems would be:
sudo apt-get install wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
To scan the container we just built run:
trivy image hadronp/ubuntu-flask:v0
To filter vulnerabilities via severity level:
trivy image --severity=MEDIUM,HIGH,CRITICAL hadronp/ubuntu-flask:v0
To to ignore unfixable vulnerabilities run::
trivy image --ignore-unfixed --severity=CRITICAL hadronp/ubuntu-flask:v0
For this demo we will use Github Actions to do the following:
- Create two pipelines to trigger on
dev
andmain
branch merge events - Checkout the code for each branch
- Build the Docker image
- Use a Trivy Github Action to scan the image
- if everything goes well push the image to Alibaba Container Registry
- simulate a deployment by puling the image from the registry, run the image and then verify by invoking
curl http://localhost:5000
on the agent
In an immutable infrastructure paradigm, container images are recreated from scratch for each change in configuration and code. This ensures that each deployment in development and production environments is consistent.
Assuming new code is pushed into version control and when Pull requests are merged the pipeline goes through the defined workflow of building, scanning, registry push and deployment
MIT