Tuesday, 28 April 2020

All about Docker : Part 3


Introduction to Docker Swarm
Why Swarm
  • An enterprise grade secure cluster:
  • Manage one or more Docker nodes as a cluster
  • Encrypted distributed cluster store
  • Encrypted networks
  • Secure join tokens
  • An orchestration engine for creating mircoservices:
  • API for deploying and managing microservices
  • Declarative manifest files for defining apps
  • Provides availability to scale apps, and perform rolling updates and rollbacks
Swarm was initially a separate product layered on Docker, since Docker 1.12 it has become a part of the engine.
Swarm has two major components:
The Cluster
  • A swarm consists of one or more Docker nodes.
  • Nodes are either a managers or a worker.
  • Managers:
  • Manage the state of the cluster
  • Dispatch tasks to workers
  • Workers:
  • Accepts and execute tasks
  • State is held in etcd
  • Swarm uses Transport Layer Security (TLS):
  • Encrypted communication
  • Authenticated nodes
  • Authorized roles
Orchestration
  • The atomic unit of scheduling is a swarm service.
  • The service construct adds the following to a container:
  • scaling
  • rolling updates
  • rollback
  • updates
  • A container wrapped in a service is a task or a replica.
Running Docker in Swarm Mode
In this lesson, we will create two new docker servers. These servers will be used in a swarm configuration. Then we will initialize the swarm manager and have the two new nodes join the swarm.
Install the Swarm Worker Node
Now create two new servers in Cloud Playground that will be used as worker nodes.
Prerequisites
Uninstall old versions:
sudo yum remove -y docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
Install Docker CE
Add the Docker repository:
sudo yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2
Set up the stable repository:
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
Install Docker CE:
sudo yum -y install docker-ce
Enable and Start Docker:
sudo systemctl start docker && sudo systemctl enable docker
Add cloud_user to the docker group:
sudo usermod -aG docker cloud_user
Initialize the manager:
docker swarm init \
--advertise-addr [PRIVATE_IP]
Add the worker to the cluster:
docker swarm join --token [TOKEN] \
[PRIVATE_IP]:2377
List the nodes in the swarm:
docker node ls
Managing Swarm Nodes
Docker node commands:
  • demote: Demotes one or more nodes from manager in the swarm
  • inspect: Displays detailed information on one or more nodes
  • ls: Lists nodes in the swarm
  • promote: Promotes one or more nodes to manager in the swarm
  • ps: Lists tasks running on one or more nodes, defaults to current node
  • rm: Removes one or more nodes from the swarm
  • update: Updates a node
Docker swarm commands:
  • ca: Displays and rotate the root CA
  • init: Initializes a swarm
  • join: Joins a swarm as a node and/or manager
  • join-token: Manages join tokens
  • leave: Leaves the swarm
  • unlock: Unlocks swarm
  • unlock-key: Manages the unlock key
  • update: Updates the swarm
Managing swarm nodes:
Listing nodes:
docker node ls
Inspecting a node:
docker node inspect [NODE_NAME]
Promoting a worker to a manager:
docker node promote [NODE_NAME]
Demoting a manager to a worker:
docker node demote [NODE_NAME]
Removing a node form the swarm (node must be demoted first):
docker node rm -f [NODE_NAME]
Make a node leave the swarm:
docker swarm leave
Getting the join-token:
docker swarm join-token [worker|manager]
Make the node rejoin the swarm:
docker swarm join --token [TOKEN] \
<PRIVATE_IP>:2377
Introduction to Docker Security
Security is all about layers
Linux security:
  • Namespaces
  • Control Groups
  • Mandatory Access Control (MAC)
  • Seccomp
Docker security:
  • Docker Swarm
  • Docker Content Trust
  • Docker Security Scanner
  • Docker secrets
Namespaces
Docker creates a set of namespaces and control groups for the container. Docker containers are an organized collections of namespaces.
  • Namespaces provide isolation.
  • Each container also gets its own network stack.
Docker on Linux namespaces:
  • Process ID (pid)
  • network (net)
  • Filesystem/mount (mount)
  • Inter-process Communication (ipc)
  • User (user)
  • UTS (uts)
Control Groups
Control Groups are about setting limits for:
  • CPU
  • RAM
  • Disk I/O
They help to mitigate denial-of-service attacks, and are important on multi-tenant platforms.
Capabilities
Capabilities turn the binary “root/non-root” dichotomy into a fine-grained access control system. In most cases, containers do not need “real” root privileges at all. This means root within a container has much less privileges than the real root. It also means that even if an intruder manages to escalate to root within a container, it is much harder to do serious damage, or to escalate to the host.
Docker Swarm
Swarm Mode:
  • Cryptographic node Ids
  • Mutual authentication via TLS
  • Secure join tokens
  • CA configuration with automatic certificate rotation
  • Encrypted cluster store
  • Encrypted networks
docker swarm update --cert-expiry [INT]h
Docker Secrets
These store sensitive data like:
  • Passwords
  • TLS Certificates
  • API Keys
Secrets Workflow:
1.    A secret is created and posted to the Swarm.
2.    The secret is encrypted and stored.
3.    A service is created and the secret is attached.
4.    Secrets are stored in-flight.
5.    The secret is mounted into the container of a service.
6.    When the task is complete, the in-memory is torn down.
Working with Docker Security
In this lesson we will start implementing some of the Docker security practices.
Seccomp Profile
docker container run --security-opt seccomp=[PROFILE] [IMAGE] [CMD]
Testing Seccomp:
docker container run --rm -it alpine sh
whoami
mount /dev/sda1 /tmp
swapoff -a
Using a custom Seccomp profile:
mkdir -p seccomp/profiles/chmod
cd seccomp/profiles/chmod
wget https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json
Remove chmod, fchmod and fchmodat from the syscalls whitelist. Syscalls starts at line 52.
Applying the custom Seccomp profile:
docker container run --rm -it --security-opt seccomp=./default.json alpine sh
chmod +r /usr
Capabilities:
Dropping Capabilities:
docker container run --cap-drop=[CAPABILITY] [IMAGE] [CMD]
Test mknod:
docker container run --rm -it alpine sh
mknod /dev/random2 c 1 8
Disable mknod:
docker container run --rm -it --cap-drop=MKNOD alpine sh
mknod /dev/random2 c 1 8
Control Groups
Limiting CPU and memory:
docker container run -it --cpus=[VALUE] --memory=[VALUE][SIZE] --memory-swap [VALUE][SIZE] [IMAGE] [CMD]
Setting memory limits on a container:
docker container run -d --name resource-limits --cpus=".5" --memory=512M --memory-swap=1G rivethead42/weather-app
Inspect resource-limits:
docker container inspect resource-limits
Running Docker Bench for Security
Running Docker Bench Security:
docker container run --rm -it --network host --pid host --userns host --cap-add audit_control \
    -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
    -v /var/lib:/var/lib \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /usr/lib/systemd:/usr/lib/systemd \
    -v /etc:/etc --label docker_bench_security \
    docker/docker-bench-security
THE END..


Friday, 17 April 2020

All about Docker : Part 2

Introduction to the Dockerfile

What is the Dockerfile?
Dockerfiles are instructions. They contains all of the commands used to build an image.
  • Docker images consist of read-only layers.
  • Each represents a Dockerfile instruction.
  • Layers are stacked.
  • Each layer is a result of the changes from the previous layer.
  • Images are built using the docker image build command.
Dockerfile Layers

Dockerfile: 
FROM ubuntu:15.04 
COPY . /app 
RUN make /app 
CMD python /app/app.py
  • FROM creates a layer from the ubuntu:15.04 Docker image.
  • COPY adds files from your Docker client’s current directory.
  • RUN builds your application with make.
  • CMD specifies what command to run within the container.
Best Practices
General guidelines:
  • Keep containers as ephemeral as possible.
  • Follow Principle 6 of the 12 Factor App.
  • Avoid including unnecessary files.
  • Use .dockerignore.
  • Use multi-stage builds.
  • Don’t install unnecessary packages.
  • Decouple applications.
  • Minimize the number of layers.
  • Sort multi-line arguments.
  • Leverage build cache.
Working with Instructions
FROM: Initializes a new build stage and sets the Base Image
RUN: Will execute any commands in a new layer
CMD: Provides a default for an executing container. There can only be one CMD instruction in a Dockerfile
LABEL: Adds metadata to an image
EXPOSE: Informs Docker that the container listens on the specified network ports at runtime
ENV: Sets the environment variable <key> to the value <value>
ADD: Copies new files, directories or remote file URLs from <src> and adds them to the filesystem of the image at the path <dest>.
COPY: Copies new files or directories from <src> and adds them to the filesystem of the container at the path <dest>.
ENTRYPOINT: Allows for configuring a container that will run as an executable
VOLUME: Creates a mount point with the specified name and marks it as holding externally mounted volumes from native host or other containers
USER: Sets the user name (or UID) and optionally the user group (or GID) to use when running the image and for any RUN, CMD, and ENTRYPOINT instructions that follow it in the Dockerfile
WORKDIR: Sets the working directory for any RUN, CMD, ENTRYPOINT, COPY, and ADD instructions that follow it in the Dockerfile
ARG: Defines a variable that users can pass at build-time to the builder with the docker build command, using the --build-arg <varname>=<value> flag
ONBUILD: Adds a trigger instruction to the image that will be executed at a later time, when the image is used as the base for another build
HEALTHCHECK: Tells Docker how to test a container to check that it is still working
SHELL: Allows the default shell used for the shell form of commands to be overridden

To set up the environment:
sudo yum install git -y
mkdir docker_images
cd docker_images
mkdir corona-app
cd corona-app
git clone https://github.com/pkadre/content-corona-app.git src

Create the Dockerfile:
vi Dockerfile

Dockerfile contents:
# Create an image for the corona-app
FROM node
LABEL org.label-schema.version=v1.1
RUN mkdir -p /var/node
ADD src/ /var/node/
WORKDIR /var/node
RUN npm install
EXPOSE 3000
CMD ./bin/www

Build the corona-app image:
docker image build -t pkadre/corona-app:v1 .

List the images:
docker image ls

Create the corona-app container:
docker container run -d --name corona-app1 -p 8081:3000 pkadre/corona-app:v1

List all running containers:
docker container ls


Environment Variables
To make new software easier to run, you can use ENV to update the PATH environment variable for the software that your container installs.

Setup your environment:
cd docker_images
mkdir env
cd env

Use the --env flag to pass an environment variable when building an image:
--env [KEY]=[VALUE]

Use the ENV instruction in the Dockerfile:
ENV [KEY]=[VALUE] 
ENV [KEY] [VALUE]

Clone the corona-app:
git clone https://github.com/pkadre/content-corona-app.git src

Create the Dockerfile
vi Dockerfile

Dockerfile contents:
# Create an image for the corona-app
FROM node
LABEL org.label-schema.version=v1.1
ENV NODE_ENV="development"
ENV PORT 3000

RUN mkdir -p /var/node
ADD src/ /var/node/
WORKDIR /var/node
RUN npm install
EXPOSE $PORT
CMD ./bin/www

Create the corona-app container:
docker image build -t pkadre/corona-app:v2 .

Inspect the container to see the environment variables:
docker image inspect pkadre/corona-app:v2

Deploy the corona-dev application:
docker container run -d --name corona-dev -p 8082:3001 --env PORT=3001 pkadre/corona-app:v2

Inspect the development container to see the environment variables:
docker container inspect corona-dev

Deploy the corona-app to production:
docker container run -d --name corona-app2 -p 8083:3001 --env PORT=3001 --env NODE_ENV=production pkadre/corona-app:v2

Inspect the production container to see the environment variables:
docker container inspect corona-app2

Get the logs for corona-app2:
docker container logs corona-app2
docker container run -d --name corona-prod -p 8084:3000 --env NODE_ENV=production pkadre/corona-app:v2
Build Arguments
Use the --build-arg flag when building an image:
--build-arg [NAME]=[VALUE]

Use the ARG instruction in the Dockerfile:
ARG [NAME]=[DEFAULT_VALUE]

Navigate to the args directory:
cd docker_images
mkdir args
cd args

Clone the corona-app:
git clone https://github.com/pkadre/content-corona-app.git src

Create the Dockerfile:
vi Dockerfile

Dockerfile:
# Create an image for the corona-app
FROM node
LABEL org.label-schema.version=v1.1
ARG SRC_DIR=/var/node

RUN mkdir -p $SRC_DIR
ADD src/ $SRC_DIR
WORKDIR $SRC_DIR
RUN npm install
EXPOSE 3000
CMD ./bin/www

Create the corona-app container:
docker image build -t pkadre/corona-app:v3 --build-arg SRC_DIR=/var/code .

Inspect the image:
docker image inspect pkadre/corona-app:v3 | grep WorkingDir

Create the corona-app container:
docker container run -d --name corona-app3 -p 8085:3000 pkadre/corona-app:v3

Verify that the container is working by executing curl:
curl localhost:8085

Building Images
To build image:
docker image build -t <NAME>:<TAG> .

Useful flags:
  • -f, --file string: This is the name of the Dockerfile (Default is PATH/Dockerfile).
  • --force-rm: Always remove intermediate containers.
  • --label list: Set metadata for an image.
  • --rm: Remove intermediate containers after a successful build (default is true).
  • --ulimit ulimit: This sets ulimit options (default is []).
cd docker_images/corona-app
cp Dockerfile Dockerfile.test
docker image build -t pkadre/corona-app:path-example1 -f Dockerfile.test .
docker image build -t pkadre/corona-app:path-example2 --label com.pkadre.version=v1.8 -f Dockerfile.test .

Building image by piping the Dockerfile through STDIN:
docker image build -t <NAME>:<TAG> -<<EOF
Build instructions
EOF

Example:
docker image build -t pkadre/nginx:stind --rm -<<EOF
FROM nginx:latest
VOLUME ["/usr/share/nginx/html/"]
EOF

Building an image using a URL:
docker image build -t <NAME>:<TAG> <GIT_URL>#<REF>
docker image build -t <NAME>:<TAG> <GIT_URL>#:<DIRECTORY>
docker image build -t <NAME>:<TAG> <GIT_URL>#<REF>:<DIRECTORY>

Example:
docker image build -t pkadre/corona-app:github https://github.com/pkadre/content-corona-app.git#remote-build

Building an image from a zip file:
docker image build -t <NAME>:<TAG> - < <FILE>.tar.gz

Example:
cd docker_images
mkdir tar_image
cd tar_image
git clone https://github.com/pkadre/content-corona-app.git
cd content-corona-app
git checkout remote-build
tar -zcvf corona-app.tar.gz Dockerfile src
docker image build -t pkadre/corona-app:from-tar - < corona-app.tar.gz
Using Multi-Stage Builds
  • By default, the stages are not named
  • Stages are numbered with integers
  • Starting with 0 for the first FROM instruction
  • Name the stage by adding as to the FROM instruction
  • Reference the stage name in the COPY instruction
Set up your environment:
cd docker_images
mkdir multi-stage-builds
cd multi-stage-builds
git clone https://github.com/pkadre/content-corona-app.git src

Create the Dockerfile:
vi Dockerfile

Dockerfile contents:
# Create an image for the corona-app using multi-stage build
FROM node AS build
RUN mkdir -p /var/node/
ADD src/ /var/node/
WORKDIR /var/node
RUN npm install

FROM node:alpine
ARG VERSION=V1.1
LABEL org.label-schema.version=$VERSION
ENV NODE_ENV="production"
COPY --from=build /var/node /var/node
WORKDIR /var/node
EXPOSE 3000
ENTRYPOINT ["./bin/www"]

Build the image:
docker image build -t pkadre/corona-app:multi-stage-build --rm --build-arg VERSION=1.5 .

List images to see the size difference:
docker image ls

Create the corona-app container:
docker container run -d --name multi-stage-build -p 8087:3000 pkadre/corona-app:multi-stage-build
Tagging
Add a name and an optional tag with -t or --tag, in the name:tag format:
docker image build -t <name>:<tag>
docker image build --tag <name>:<tag>

List your images:
docker image ls

Use our Git commit hash as the image tag:
git log -1 --pretty=%H

Use the Docker tag to a create a new tagged image:
docker tag <SOURCE_IMAGE><:TAG> <TARGET_IMAGE>:<TAG>

Get the commit hash:
cd docker_images/corona-app/src
git log -1 --pretty=%H
cd ../

Build the image using the Git hash as the tag:
docker image build -t pkadre/corona-app:<GIT_HASH> .

Tag the corona-app as the latest using the image tagged with the commit hash:
docker image tag pkadre/corona-app:<GIT_HASH> pkadre/corona-app:latest
Docker Events
Get real-time events from the server:
docker system events
docker system events --since '<TIME_PERIOD>'

Start a new CentOS container:
docker container run -itd --name docker_events centos /bin/bash

Listen for events:
docker system events

Generate Events:
docker container exec docker_events /bin/bash
docker container attach docker_events
docker container start docker_events

Filters Events:
docker system events --filter <FILTER_NAME>=<FILTER>

Filter for container events:
docker system events --filter type=container --since '1h'

Generate an event:
docker container exec docker_events ls /

Filter for container events:
docker system events --filter type=container --filter event=start --since '1h'

List / on docker_events:
docker container exec docker_events ls /

Filter for attach events:
docker system events --filter type=container --filter event=attach

Connect to docker_events using /bin/bash:
docker container exec -it docker_events /bin/bash

Attach to docker_events:
docker container attach docker_events

Connect to docker_events using /bin/bash:
docker container exec -it docker_events /bin/bash

Attach to docker_events:
docker container attach docker_events

Use multiple filters:
docker system events --filter type=container --filter event=attach --filter event=die --filter event=stop

Start docker_events:
docker container start docker_events

Attach to docker_events:
docker container attach docker_events

Documentation
https://docs.docker.com/engine/reference/commandline/events/
https://docs.docker.com/engine/api/v1.24/
Managing Stopped Container
Remove one or more containers:
docker container rm <NAME>

List the rm flags:
docker container rm -h

Start one or more stopped containers:
docker container start <NAME>

Remove all stopped containers:
docker container prune

List the IDs of all containers:
docker container ls -a -q

List all stopped containers:
docker container ls -a -f status=exited

List the IDs of stopped containers:
docker container ls -a -q -f status=exited

Get a count of all stopped containers:
docker container ls -a -q -f status=exited | wc -l

Get a listing of our containers:
docker container ls -a -f status=exited | grep prometheus

Start Prometheus:
docker container start prometheus

Fin stopped corona-app containers with grep:
docker container ls -a -f status=exited | grep corona-app

Remove stopped corona-app containers:
docker container rm [CONTAINER_IDS]

Prune all stopped containers:
docker container prune