Docker – Security

There are four major areas to consider when reviewing Docker security:

  • the intrinsic security of the kernel and its support for namespaces and cgroups;
  • the attack surface of the Docker daemon itself;
  • loopholes in the container configuration profile, either by default, or when customized by users.
  • the “hardening” security features of the kernel and how they interact with containers.

Kernel namespaces

Docker containers are very similar to LXC containers, and they have similar security features. When you start a container with docker run, behind the scenes Docker creates a set of namespaces and control groups for the container.

Namespaces provide the first and most straightforward form of isolation: processes running within a container cannot see, and even less affect, processes running in another container, or in the host system.

Each container also gets its own network stack, meaning that a container doesn’t get privileged access to the sockets or interfaces of another container. Of course, if the host system is setup accordingly, containers can interact with each other through their respective network interfaces — just like they can interact with external hosts. When you specify public ports for your containers or use links then IP traffic is allowed between containers. They can ping each other, send/receive UDP packets, and establish TCP connections, but that can be restricted if necessary. From a network architecture point of view, all containers on a given Docker host are sitting on bridge interfaces. This means that they are just like physical machines connected through a common Ethernet switch; no more, no less.

Control groups

Control Groups are another key component of Linux Containers. They implement resource accounting and limiting. They provide many useful metrics, but they also help ensure that each container gets its fair share of memory, CPU, disk I/O; and, more importantly, that a single container cannot bring the system down by exhausting one of those resources.

So while they do not play a role in preventing one container from accessing or affecting the data and processes of another container, they are essential to fend off some denial-of-service attacks. They are particularly important on multi-tenant platforms, like public and private PaaS, to guarantee a consistent uptime (and performance) even when some applications start to misbehave.

Control Groups have been around for a while as well: the code was started in 2006, and initially merged in kernel 2.6.24.

Docker daemon attack surface

Running containers (and applications) with Docker implies running the Docker daemon. This daemon requires root privileges unless you opt-in to Rootless mode (experimental), and you should therefore be aware of some important details.

First of all, only trusted users should be allowed to control your Docker daemon. This is a direct consequence of some powerful Docker features. Specifically, Docker allows you to share a directory between the Docker host and a guest container; and it allows you to do so without limiting the access rights of the container. This means that you can start a container where the /host directory is the / directory on your host; and the container can alter your host filesystem without any restriction. This is similar to how virtualization systems allow filesystem resource sharing. Nothing prevents you from sharing your root filesystem (or even your root block device) with a virtual machine.

This has a strong security implication: for example, if you instrument Docker from a web server to provision containers through an API, you should be even more careful than usual with parameter checking, to make sure that a malicious user cannot pass crafted parameters causing Docker to create arbitrary containers.

For this reason, the REST API endpoint (used by the Docker CLI to communicate with the Docker daemon) changed in Docker 0.5.2, and now uses a UNIX socket instead of a TCP socket bound on 127.0.0.1 (the latter being prone to cross-site request forgery attacks if you happen to run Docker directly on your local machine, outside of a VM). You can then use traditional UNIX permission checks to limit access to the control socket.

You can also expose the REST API over HTTP if you explicitly decide to do so. However, if you do that, be aware of the above mentioned security implications. Note that even if you have a firewall to limit accesses to the REST API endpoint from other hosts in the network, the endpoint can be still accessible from containers, and it can easily result in the privilege escalation. Therefore it is mandatory to secure API endpoints with HTTPS and certificates. It is also recommended to ensure that it is reachable only from a trusted network or VPN.

You can also use DOCKER_HOST=ssh://USER@HOST or ssh -L /path/to/docker.sock:/var/run/docker.sock instead if you prefer SSH over TLS.

The daemon is also potentially vulnerable to other inputs, such as image loading from either disk with docker load, or from the network with docker pull. As of Docker 1.3.2, images are now extracted in a chrooted subprocess on Linux/Unix platforms, being the first-step in a wider effort toward privilege separation. As of Docker 1.10.0, all images are stored and accessed by the cryptographic checksums of their contents, limiting the possibility of an attacker causing a collision with an existing image.

Finally, if you run Docker on a server, it is recommended to run exclusively Docker on the server, and move all other services within containers controlled by Docker. Of course, it is fine to keep your favorite admin tools (probably at least an SSH server), as well as existing monitoring/supervision processes, such as NRPE and collectd.

Linux kernel capabilities

By default, Docker starts containers with a restricted set of capabilities. What does that mean?

Capabilities turn the binary “root/non-root” dichotomy into a fine-grained access control system. Processes (like web servers) that just need to bind on a port below 1024 do not need to run as root: they can just be granted the net_bind_service capability instead. And there are many other capabilities, for almost all the specific areas where root privileges are usually needed.

This means a lot for container security; let’s see why!

Typical servers run several processes as root, including the SSH daemon, cron daemon, logging daemons, kernel modules, network configuration tools, and more. A container is different, because almost all of those tasks are handled by the infrastructure around the container:

  • SSH access are typically managed by a single server running on the Docker host;
  • cron, when necessary, should run as a user process, dedicated and tailored for the app that needs its scheduling service, rather than as a platform-wide facility;
  • log management is also typically handed to Docker, or to third-party services like Loggly or Splunk;
  • hardware management is irrelevant, meaning that you never need to run udevd or equivalent daemons within containers;
  • network management happens outside of the containers, enforcing separation of concerns as much as possible, meaning that a container should never need to perform ifconfigroute, or ip commands (except when a container is specifically engineered to behave like a router or firewall, of course).

This means that in most cases, containers do not need “real” root privileges at all. And therefore, containers can run with a reduced capability set; meaning that “root” within a container has much less privileges than the real “root”. For instance, it is possible to:

  • deny all “mount” operations;
  • deny access to raw sockets (to prevent packet spoofing);
  • deny access to some filesystem operations, like creating new device nodes, changing the owner of files, or altering attributes (including the immutable flag);
  • deny module loading;
  • and many others.

This 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.

This doesn’t affect regular web apps, but reduces the vectors of attack by malicious users considerably. By default Docker drops all capabilities except those needed, an allowlist instead of a denylist approach. You can see a full list of available capabilities in Linux man pages.

One primary risk with running Docker containers is that the default set of capabilities and mounts given to a container may provide incomplete isolation, either independently, or when used in combination with kernel vulnerabilities.

Docker supports the addition and removal of capabilities, allowing use of a non-default profile. This may make Docker more secure through capability removal, or less secure through the addition of capabilities. The best practice for users would be to remove all capabilities except those explicitly required for their processes.

Docker Content Trust Signature Verification

The Docker Engine can be configured to only run signed images. The Docker Content Trust signature verification feature is built directly into the dockerd binary.
This is configured in the Dockerd configuration file.

To enable this feature, trustpinning can be configured in daemon.json, whereby only repositories signed with a user-specified root key can be pulled and run.

This feature provides more insight to administrators than previously available with the CLI for enforcing and performing image signature verification.

References:

  1. https://docs.docker.com
  2. from Miscellaneous technical websites.

Docker – compose

Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.

Using Compose is basically a three-step process:

  1. Define your app’s environment with a Dockerfile so it can be reproduced anywhere.
  2. Define the services that make up your app in docker-compose.yml so they can be run together in an isolated environment.
  3. Run docker-compose up and Compose starts and runs your entire app.

Install Compose on Linux systems

On Linux, you can download the Docker Compose binary from the Compose repository release page on GitHub. Follow the instructions from the link, which involve running the curl command in your terminal to download the binaries. These step-by-step instructions are also included below.

For alpine, the following dependency packages are needed: py-pip, python-dev, libffi-dev, openssl-dev, gcc, libc-dev, and make.

  1. Run this command to download the current stable release of Docker Compose:
sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

To install a different version of Compose, substitute 1.27.4 with the version of Compose you want to use.

  • Apply executable permissions to the binary:
sudo chmod +x /usr/local/bin/docker-compose

Note: If the command docker-compose fails after installation, check your path. You can also create a symbolic link to /usr/bin or any other directory in your path.

For example:

sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
  1. Optionally, install command completion for the bash and zsh shell.
  2. Test the installation.
$ docker-compose --version
docker-compose version 1.27.4, build 1110ad01

Uninstallation

To uninstall Docker Compose if you installed using curl:

$ sudo rm /usr/local/bin/docker-compose

To uninstall Docker Compose if you installed using pip:

$ pip uninstall docker-compose

How to Deploy Application using Docker-Compose

Step: 1

Create application folder and place the code in that Folder.

Step: 2

Create Dockerfile to create Docker Image for mentioned Source code in Step 1.

e.g.:

Dockerfile

FROM python:3.7-alpine

WORKDIR /app

ENV FLASK_APP=app.py

ENV FLASK_RUN_HOST=127.0.0.1

COPY requirements.txt requirements.txt

RUN pip3 install -r requirements.txt

EXPOSE 5000

COPY . .

CMD [“flask”, “run”]

Step 3: Define services in a Compose file

Create a file called docker-compose.yml in your project directory and paste the following:

version: "3.8"
services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

This Compose file defines two services: web and redis.

Web service

The web service uses an image that’s built from the Dockerfile in the current directory. It then binds the container and the host machine to the exposed port, 5000. This example service uses the default port for the Flask web server, 5000.

Redis service

The redis service uses a public Redis image pulled from the Docker Hub registry.

From your project directory, start up your application by running docker-compose up.

$ docker-compose up

Creating network “composetest_default” with the default driver

Creating composetest_web_1 …

Creating composetest_redis_1 …

Creating composetest_web_1

Creating composetest_redis_1 … done

Attaching to composetest_web_1, composetest_redis_1

web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

redis_1  | 1:C 17 Aug 22:11:10.480 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo

redis_1  | 1:C 17 Aug 22:11:10.480 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1, just started

redis_1  | 1:C 17 Aug 22:11:10.480 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf

web_1    |  * Restarting with stat

redis_1  | 1:M 17 Aug 22:11:10.483 * Running mode=standalone, port=6379.

web_1    |  * Debugger is active!

redis_1  | 1:M 17 Aug 22:11:10.483 # Server initialized

web_1    |  * Debugger PIN: 330-787-903

redis_1  | 1:M 17 Aug 22:11:10.483 * Ready to accept connections

Compose pulls a Redis image, builds an image for your code, and starts the services you defined. In this case, the code is statically copied into the image at build time.

  • Enter http://localhost:5000/ in a browser to see the application running.

If you’re using Docker natively on Linux, Docker Desktop for Mac, or Docker Desktop for Windows, then the web app should now be listening on port 5000 on your Docker daemon host. Point your web browser to http://localhost:5000 to find the Hello World message. If this doesn’t resolve, you can also try http://127.0.0.1:5000.

If you want to run your services in the background, you can pass the -d flag (for “detached” mode) to docker-compose up and use docker-compose ps to see what is currently running:

$ docker-compose up -d
Starting composetest_redis_1...
Starting composetest_web_1...
$ docker-compose ps
Name                 Command            State       Ports
composetest_redis_1   /usr/local/bin/run         Up
composetest_web_1     /bin/sh -c python app.py   Up      5000->5000/tcp

The docker-compose run command allows you to run one-off commands for your services. For example, to see what environment variables are available to the web service:

$ docker-compose run web env

See docker-compose --help to see other available commands. You can also install command completion for the bash and zsh shell, which also shows you available commands.

If you started Compose with docker-compose up -d, stop your services once you’ve finished with them:

$ docker-compose stop

You can bring everything down, removing the containers entirely, with the down command. Pass --volumes to also remove the data volume used by the Redis container:

$ docker-compose down --volumes

Control startup and shutdown order in Compose

You can control the order of service startup and shutdown with the depends on option. Compose always starts and stops containers in dependency order, where dependencies are determined by depends_onlinksvolumes_from, and network_mode: "service:...".

However, for startup Compose does not wait until a container is “ready” 

For example, to use wait-for-it.sh or wait-for to wrap your service’s command:

version: “2”

services:

  web:

    build: .

    ports:

      – “80:8000”

    depends_on:

      – “db”

    command: [“./wait-for-it.sh”, “db:5432”, “–“, “python”, “app.py”]

  db:

    image: postgres

Above compose file create web service post db service creation.

References:

  1. https://docs.docker.com
  2. from Miscellaneous technical websites.

How to Take Backup and Restore of Docker Container

Backup a container

For example, create a new container named dbstore:

# docker run -v /dbdata --name dbstore ubuntu /bin/bash

Then in the next command, we:

  • Launch a new container and mount the volume from the dbstore container
  • Mount a local host directory as /backup
  • Pass a command that tars the contents of the dbdata volume to a backup.tar file inside our /backup directory.
# docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

When the command completes and the container stops, we are left with a backup of our dbdata volume.

Restore container from backup

With the backup just created, you can restore it to the same container, or another that you made elsewhere.

For example, create a new container named dbstore2:

# docker run -v /dbdata --name dbstore2 ubuntu /bin/bash

Then un-tar the backup file in the new container`s data volume:

# docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"

You can use the techniques above to automate backup, migration and restore testing using your preferred tools.

References:

  1. https://docs.docker.com
  2. from Miscellaneous technical websites.

Docker – storage and volumes

By default all files created inside a container are stored on a writable container layer. This means that:

  • The data doesn’t persist when that container no longer exists, and it can be difficult to get the data out of the container if another process needs it.
  • A container’s writable layer is tightly coupled to the host machine where the container is running. You can’t easily move the data somewhere else.
  • Writing into a container’s writable layer requires a storage driver to manage the filesystem. The storage driver provides a union filesystem, using the Linux kernel. This extra abstraction reduces performance as compared to using data volumes, which write directly to the host filesystem.

Docker has two options for containers to store files in the host machine, so that the files are persisted even after the container stops: volumes, and bind mounts

  • Volumes are stored in a part of the host filesystem which is managed by Docker (/var/lib/docker/volumes/ on Linux). Non-Docker processes should not modify this part of the filesystem. Volumes are the best way to persist data in Docker.
  • Bind mounts may be stored anywhere on the host system. They may even be important system files or directories. Non-Docker processes on the Docker host or a Docker container can modify them at any time.
  • tmpfs mounts are stored in the host system’s memory only, and are never written to the host system’s filesystem.

Volumes: Created and managed by Docker. You can create a volume explicitly using the docker volume create command, or Docker can create a volume during container or service creation. When you create a volume, it is stored within a directory on the Docker host. When you mount the volume into a container, this directory is what is mounted into the container. 

Bind mounts: Available since the early days of Docker. Bind mounts have limited functionality compared to volumes. When you use a bind mount, a file or directory on the host machine is mounted into a container. The file or directory is referenced by its full path on the host machine. The file or directory does not need to exist on the Docker host already. 

Choose the -v or –mount flag

In general, --mount is more explicit and verbose. The biggest difference is that the -v syntax combines all the options together in one field, while the --mount syntax separates them. Here is a comparison of the syntax for each flag.

If you need to specify volume driver options, you must use --mount.

  • -v or --volume: Consists of three fields, separated by colon characters (:). The fields must be in the correct order, and the meaning of each field is not immediately obvious.
    • In the case of named volumes, the first field is the name of the volume, and is unique on a given host machine. For anonymous volumes, the first field is omitted.
    • The second field is the path where the file or directory are mounted in the container.
    • The third field is optional, and is a comma-separated list of options, such as ro. These options are discussed below.
  • --mount: Consists of multiple key-value pairs, separated by commas and each consisting of a <key>=<value> tuple. The --mount syntax is more verbose than -v or --volume, but the order of the keys is not significant, and the value of the flag is easier to understand.
    • The type of the mount, which can be bind, volume, or tmpfs. This topic discusses volumes, so the type is always volume.
    • The source of the mount. For named volumes, this is the name of the volume. For anonymous volumes, this field is omitted. May be specified as source or src.
    • The destination takes as its value the path where the file or directory is mounted in the container. May be specified as destinationdst, or target.
    • The readonly option, if present, causes the bind mount to be mounted into the container as read-only.
    • The volume-opt option, which can be specified more than once, takes a key-value pair consisting of the option name and its value.

Differences between -v and --mount behavior

As opposed to bind mounts, all options for volumes are available for both --mount and -v flags.

When using volumes with services, only --mount is supported.

Create and manage volumes

Unlike a bind mount, you can create and manage volumes outside the scope of any container.

  • Create a volume:
# docker volume create my-vol
  • List volumes:
# docker volume ls
local               my-vol
  • Inspect a volume:
# docker volume inspect my-vol
  • Remove a volume:
# docker volume rm my-vol
  • Example of mount:
# docker run -d --name test --mountsource=myvol,target=/app \ nginx:latest
  • Example of volume mounts:
# docker run -d --name test -v myvol:/app nginx:latest
  • To remove volume:

Stop and remove the container, and remove the volume. Volume removal is a separate step.

# docker container stop nginxtest
# docker container rm nginxtest
# docker volume rm nginx-vol

Start a service with volumes

# docker service create -d --replicas=4 --name test-service \        --mountsource=myvol,target=/testapp nginx:latest

Remove volumes

A Docker data volume persists after a container is deleted. There are two types of volumes to consider:

  • Named volumes have a specific source from outside the container, for example awesome:/car.
  • Anonymous volumes have no specific source so when the container is deleted, instruct the Docker Engine daemon to remove them.

Remove anonymous volumes

To automatically remove anonymous volumes, use the --rm option. For example, this command creates an anonymous /foo volume. When the container is removed, the Docker Engine removes the /foo volume but not the awesome volume.

# docker run --rm -v /doo -v awesome:/car busytool top

Remove all volumes

To remove all unused volumes and free up space:

# docker volume prune

References:

  1. https://docs.docker.com
  2. from Miscellaneous technical websites.

Docker – Networking

Docker takes care of the networking aspects so that the containers can communicate with other containers and also with the Docker Host. When Docker is installed, a default bridge network named  docker0 is created. Each new Docker container is automatically attached to this network, unless a custom network is specified.

Docker comes with network drivers geared towards different use cases. The most common network types being:  bridge,  overlay, and host.

Bridge networking is the most common network type. It is limited to containers within a single host running the Docker engine. Bridge networks are easy to create, manage and troubleshoot.

For the containers on bridge network to communicate or be reachable from the outside world, port mapping needs to be configured.

To create a bridge network named  my-bridge-net  , pass the argument  bridge  to the  -d  (driver) parameter as shown below:

# docker network create -d bridge my-bridge-net

An overlay network uses software virtualization to create additional layers of network abstraction running on top of a physical network. In Docker, an overlay network driver is used for multi-host network communication. This driver utilizes Virtual Extensible LAN (VXLAN) technology which provide portability between cloud, on-premise and virtual environments. VXLAN solves common portability limitations by extending layer 2 subnets across layer 3 network boundaries, hence containers can run on foreign IP subnets.

To Create Network

To create an overlay network named my-overlay-net, you’ll also need the –subnet parameter to specify the network block that Docker will use to assign IP addresses to the containers:

# docker network create -d overlay –subnet=192.168.10.0/24 my-overlay-net

Some common operations with Docker networking include:

  • Inspect a network: To see a specific network’s configuration details like subnet information, network name, IPAM driver, network ID, network driver, or connected containers, use the docker network inspect command.
  • List all networks: Run docker network ls to display all networks (along with their type and scope) present on the current host.
  • Create a new network: To create a new network, use the docker network create command and specify if it’s of type bridge (default), overlay or macvlan.
  • Run or connect a container to a specific network: Note first of all, the network must exist already on the host. Either specify the network at container creation/startup time (docker create or docker run) with the –net option; or attach an existing container by using the docker network connect command. For example:

# docker network connect my-network my-container

  • Disconnect a container from a network: The container must be running to disconnect it from the network using the docker network disconnect command.
  • Remove an existing network: A network can only be removed using the command docker network rm if there are no containers attached to it. When a network is removed, the associated bridge will be removed as well.

Directly linking containers

It is possible to directly link one container to another using the –link option when starting a container. This allow containers to discover each other and securely transfer information about one container to another container. However, Docker has deprecated this feature and recommends creating user-defined networks instead.

As an example, imagine you have a mydb container running a database service. We can then create an application container named myweb and directly link it to mydb:

# docker run –name myweb –link mydb:mydb -d -P myapp python app.py

References:

  1. https://docs.docker.com
  2. from Miscellaneous technical websites.

Docker Orchestration (Swarm)

Orchestration is the automatic process of managing or scheduling the work of individual containers for applications based on micro services within multiple clusters. The widely deployed container orchestration platforms are based on open-source versions like Kubernetes, Docker Swarm.

Why We Need Container Orchestration?

Container orchestration is used to automate the following tasks at scale:
• Configuring and scheduling of containers
• Provisioning and deployments of containers
• Availability of containers
• The configuration of applications in terms of the containers that they run in
• Scaling of containers to equally balance application workloads across infrastructure
• Allocation of resources between containers
• Load balancing, traffic routing and service discovery of containers
• Health monitoring of containers
• Securing the interactions between containers.

Container orchestration works with tools like Kubernetes and Docker Swarm. Configurations files tell the container orchestration tool how to network between containers and where to store logs. The orchestration tool also schedules deployment of containers into clusters and determines the best host for the container. After a host is decided, the orchestration tool manages the lifecycle of the container based on predetermined specifications. Container orchestration tools work in any environment that runs containers.

Orchestration tools for Docker include the following:


Docker Machine — Provisions hosts and installs Docker Engine.
Docker Swarm — Clusters multiple Docker hosts under a single host. It can also integrate with any tool that works with a single Docker host.
Docker Compose — Deploys multi-container applications by creating the required containers.

A swarm consists of multiple Docker hosts which run in swarm mode and act as managers (to manage membership and delegation) and workers (which run swarm services). A node is an instance of the Docker engine participating in the swarm. To deploy your application to a swarm, you submit a service definition to a manager node. The manager node dispatches units of work called tasks to worker nodes.

service is the definition of the tasks to execute on the manager or worker nodes. It is the central structure of the swarm system and the primary root of user interaction with the swarm.

When you create a service, you specify which container image to use and which commands to execute inside running containers.

Join as a worker node

The Docker Engine joins the swarm depending on the join-token you provide to the docker swarm join command. The node only uses the token at join time.

# docker swarm join-token worker
To add a worker to this swarm, run the following command:
 # docker swarm join --token ********** (use same token generated while initialize master) 192.168.200.9:2044
# docker swarm join-token manager

List nodes

# docker node ls
ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
46aqrk4bt745z53cr3t    node-3    Ready   Active        Reachable
a5b2m3391pefq5u    node-2    Ready   Active   Reachable
ehkv3bcie79dn78otj5 *  node-1    Ready   Active        Leader

Create a service

To create a single-replica service with no extra configuration, you only need to supply the image name. This command starts an Nginx service with a randomly-generated name and no published ports. This is a naive example, since you can’t interact with the Nginx service.

$ docker service create nginx

The service is scheduled on an available node. To confirm that the service was created and started successfully, use the docker service ls command:

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                                                                             PORTS
a3mjhts1lxuem        quizzical_lamarr    replicated          1/1                 docker.io/library/nginx

To provide a name for your service, use the --name flag:

$ docker service create --name my_web nginx

Update a service

You can change almost everything about an existing service using the docker service update command. When you update a service, Docker stops its containers and restarts them with the new configuration.

Since Nginx is a web service, it works much better if you publish port 80 to clients outside the swarm. You can specify this when you create the service, using the -p or --publish flag. When updating an existing service, the flag is --publish-add. There is also a --publish-rm flag to remove a port that was previously published.

$ docker service update --publish-add 80 my_web

To verify that it worked, use docker service ls:

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                                                                          PORTS
4nhxl7oxw5vz        my_web              replicated          1/1                 docker.io/library/nginx@sha256:

Remove a service

To remove a service, use the docker service remove command. You can remove a service by its ID or name, as shown in the output of the docker service ls command. The following command removes the my_web service.

$ docker service remove my_web

Docker Service Child commands

CommandDescription
docker service createCreate a new service
docker service inspectDisplay detailed information on one or more services
docker service logsFetch the logs of a service or task
docker service lsList services
docker service psList the tasks of one or more services
docker service rmRemove one or more services
docker service rollbackRevert changes to a service’s configuration
docker service scaleScale one or multiple replicated services
docker service updateUpdate a service

Docker service create (options)

–detach , -dExit immediately instead of waiting for the service to converge
–env , -eSet environment variables
–hostnameContainer hostname
–limit-cpuLimit CPUs
–limit-memoryLimit Memory
–log-driverLogging driver for service
-modereplicatedService mode (replicated or global)
–mountAttach a filesystem mount to the service
–nameService name
–networkNetwork attachments
–publish , -pPublish a port as a node port
–tty , -tAllocate a pseudo-TTY
# docker service create --name redis --replicas=5 redis:3.0.6

Above Command Create a service with name redis with 5 replicas using redis:3.0.6 docker image.

References:

  1. https://docs.docker.com
  2. from Miscellaneous technical websites.

Docker – Images and containers

An image is a read-only template with instructions for creating a Docker container. Often, an image is based on another image, with some additional customization.

A Docker image is made up of a collection of files that bundle together all the essentials, such as installations, application code and dependencies, required to configure a fully operational container environment.

You can create a Docker image in one of two ways:

  • Interactive Method: By running a container from an existing Docker image, manually changing that container environment through a series of live steps and saving the resulting state as a new image.
  • Dockerfile Method: By constructing a plain-text file, known as a Dockerfile, which provides the specifications for creating a Docker image.

A container is a runnable instance of an image. You can create, start, stop, move, or delete a container using the Docker API or CLI. You can connect a container to one or more networks, attach storage to it, or even create a new image based on its current state.

Image Layers

Each of the files that make up a Docker image is known as a layer. These layers form a series of intermediate images, built one on top of the other in stages, where each layer is dependent on the layer immediately below it.

This is because, when you make changes to a layer in your image, Docker not only rebuilds that particular layer but all layers built from it. Therefore a change to a layer at the top of the stack involves the least amount of computational work to rebuild the entire image.

Container Layer

Each time Docker launches a container from an image, it adds a thin writable layer, known as the container layer, which stores all changes to the container throughout its runtime.

Below Commands used for Docker Image Creation in Dockerfile:

CommandPurpose
FROMTo specify the parent image.
WORKDIRTo set the working directory for any commands that follow in the Dockerfile.
RUNTo install any applications and packages required for your container.
COPYTo copy over files or directories from a specific location.
ADDAs COPY, but also able to handle remote URLs and unpack compressed files.
ENTRYPOINTCommand that will always be executed when the container starts. If not specified, the default is /bin/sh –c
CMDArguments passed to the entrypoint. If ENTRYPOINT is not set (defaults to /bin/sh -c), the CMD will be the commands the container executes.
EXPOSETo define which port through which to access your container application.

Example Dockerfile

FROM ubuntu:16.04

RUN apt-get update &&
apt-get install -y nginx curl   # Install nginx and curl


Below are some command examples:

  • Run below command to create image

# docker build –t image_name:tag .

e.g. docker build –t testimage:latest .

  • List available images:

# docker images

REPOSITORY     TAG  IMAGE ID        CREATED        SIZE

nginx       0.4  f45ae2g1355b    1 seconds ago 148MB

ubuntu         16.04 ddd6e57d412v  12 days ago    62.2MB

  • To remove docker images:

# docker rmi image_name/image_ID

  • To get Help on docker build Run below command

# docker build –help

  • To check image layers

# docker history image_ID/name

  • To get more details about Image

# docker image inspect Image_ID/name

  • To run Container using docker image

# docker run –name container_name Image_name:tag

# docker run –d –p 8080:8085 –name test test:latest

Above command run container named test in detach mode from test:latest image with publishing port 8085 from container to bind 8080 host port.

  • To check all running container status:

# docker ps

  • To check all container status:

# docker ps –a

  • To login in container:

# docker exec –it container_id shell(eg sh/bash)

  • To run command in specified container:

# docker exec container_id command

Options used in “docker run” command:

–cpusNumber of CPUs
–env , -eSet environment variables
–exposeExpose a port or a range of ports
–helpPrint usage
–interactive , -iKeep STDIN open even if not attached
–memory , -mMemory limit
–mount Attach a filesystem mount to the container
–name Assign a name to the container
–publish , -p Publish a container’s port(s) to the host
–tty , -t Allocate a pseudo-TTY
–volume , -v Bind mount a volume
–workdir , -w Working directory inside the container
–volumes-from Mount volumes from the specified container(s)

References:

  1. https://docs.docker.com
  2. from Miscellaneous technical websites.

Docker – Basic

Docker is a set of platform as a service product that use OS-level virtualization to deliver software in packages called containers. Containers are isolated from one another and bundle their own software, libraries and configuration files; they can communicate with each other through well-defined channels.

Docker provides the ability to package and run an application in a loosely isolated environment called a container. The isolation and security allow you to run many containers simultaneously on a given host.

Docker architecture

Docker uses a client-server architecture. The Docker client talks to the Docker daemon, which does the heavy lifting of building, running, and distributing your Docker containers. The Docker client and daemon can run on the same system, or you can connect a Docker client to a remote Docker daemon. The Docker client and daemon communicate using a REST API, over UNIX sockets or a network interface.

The Docker daemon

The Docker daemon (dockerd) listens for Docker API requests and manages Docker objects such as images, containers, networks, and volumes. A daemon can also communicate with other daemons to manage Docker services.

The Docker client

The Docker client (docker) is the primary way that many Docker users interact with Docker. When you use commands such as docker run, the client sends these commands to dockerd, which carries them out. The docker command uses the Docker API. The Docker client can communicate with more than one daemon.

Docker registries

A Docker registry stores Docker images. Docker Hub is a public registry that anyone can use, and Docker is configured to look for images on Docker Hub by default. You can even run your own private registry.

When you use the docker pull or docker run commands, the required images are pulled from your configured registry. When you use the docker push command, your image is pushed to your configured registry.

SERVICES

Services allow you to scale containers across multiple Docker daemons, which all work together as a swarm with multiple managers and workers. Each member of a swarm is a Docker daemon, and all the daemons communicate using the Docker API. A service allows you to define the desired state, such as the number of replicas of the service that must be available at any given time. By default, the service is load-balanced across all worker nodes.

Namespaces

Docker uses a technology called namespaces to provide the isolated workspace called the container. When you run a container, Docker creates a set of namespaces for that container.

These namespaces provide a layer of isolation.

Control groups

Docker Engine on Linux also relies on another technology called control groups (cgroups). A cgroup limits an application to a specific set of resources.

Docker Engine is a client-server application with these major components:

  • A server which is a type of long-running program called a daemon process (the dockerd command).
  • A REST API which specifies interfaces that programs can use to talk to the daemon and instruct it what to do.
  • A command line interface (CLI) client (the docker command).

How Does Docker Works?

Docker works on a client-server architecture. It includes the docker client, docker host, and docker registry. The docker client is used for triggering docker commands, docker host is used to running the docker daemon, and docker registry to store docker images.

The docker client communicates to docker daemon using a REST API, which internally supports to build, run, and distribute docker containers. Both the client and daemon can run on the same system or can be connected remotely.

References:

  1. https://docs.docker.com
  2. from Miscellaneous technical websites.

Boot process of Linux System

Below are the basic stages of the boot process for an x86 system:

  1. The system BIOS checks the system and launches the first stage boot loader on the MBR of the primary hard disk.
  2. The first stage boot loader loads itself into memory and launches the second stage boot loader from the /boot/ partition.
  3. The second stage boot loader loads the kernel into memory, which in turn loads any necessary modules and mounts the root partition read-only.
  4. The kernel transfers control of the boot process to the /sbin/init program.
  5. The /sbin/init program loads all services and user-space tools, and mounts all partitions listed in /etc/fstab.
  6. The user is presented with a login screen for the freshly booted Linux system.

Detailed Process:

BIOS :

The BIOS controls not only the first step of the boot process, but also provides the lowest level interface to peripheral devices. For this reason it is written into read-only, permanent memory and is always available for use.

The BIOS then loads into memory a program is residing in the first sector of this device, called the Master Boot Record or MBR. The MBR is only 512 bytes in size and contains machine code instructions for booting the machine, called a boot loader, along with the partition table. Once the BIOS finds and loads the boot loader program into memory, it yields control of the boot process to it.

Boot loader :

The default boot loader for the x86 platform, GRUB

GRUB has the advantage of being able to read ext2 and ext3  partitions and load its configuration file — /boot/grub/grub.conf — at boot time

A boot loader for the x86platform is broken into at least two stages. The first stage is a small machine code binary on the MBR. Its sole job is to locate the second stage boot loader and load the first part of it into memory.

Once the second stage boot loader is in memory, it presents the user with a graphical screen showing the different operating systems or kernels it has been configured to boot. On this screen a user can use the arrow keys to choose which operating system or kernel they wish to boot and press Enter. If no key is pressed, the boot loader loads the default selection after a configurable period of time has passed

Boot Loaders:

Once the kernel loads and hands off the boot process to the init command, The boot loader then places one or more appropriate initramfs images into memory. Next, the kernel decompresses these images from memory to /boot/, a RAM-based virtual file system, via cpio. The initramfs is used by the kernel to load drivers and modules necessary to boot the system. This is particularly important if SCSI hard drives are present or if the systems use the ext3 file system.

Once the kernel and the initramfs image(s) are loaded into memory, the boot loader hands control of the boot process to the kernel.

The Kernel:

When the kernel is loaded, it immediately initializes and configures the computer’s memory and configures. The various hardware attached to the system, including all processors, I/O subsystems, and storage devices. It then looks for the compressed initramfs image(s) in a predetermined location in memory, decompresses it directly to /sysroot/, and loads all necessary drivers. Next, it initializes virtual devices related to the file system, such as LVM or software RAID, before completing the initramfs processes and freeing up all the memory the disk image once occupied.

At this point, the kernel is loaded into memory and operational. However, since there are no user applications that allow meaningful input to the system, not much can be done with the system.

To set up the user environment, the kernel executes the /sbin/init program.

The /sbin/init Program

The /sbin/init program (also called init) coordinates the rest of the boot process and configures the environment for the user.

When the init command starts, it becomes the parent or grandparent of all of the processes that start up automatically on the system. First, it runs the /etc/rc.d/rc.sysinit script, which sets the environment path, starts swap, checks the file systems, and executes all other steps required for system initialization

The init command then runs the /etc/inittab script, which describes how the system should be set up in each SysV init runlevel. Runlevels are a state, or mode, defined by the services listed in the SysV /etc/rc.d/rc<x>.d/ directory, where <x> is the number of the runlevel.

the init command sets the source function library, /etc/rc.d/init.d/functions, for the system, which configures how to start, kill, and determine the PID of a program.

The init program starts all of the background processes by looking in the appropriate rc directory for the runlevel specified as the default in /etc/inittab. The rc directories are numbered to correspond to the runlevel they represent. For instance, /etc/rc.d/rc5.d/ is the directory for runlevel 5.

When booting to runlevel 5, the init program looks in the /etc/rc.d/rc5.d/ directory to determine which processes to start and stop.

The name of each symbolic link begins with either a K or an S. The K links are processes that are killed on that runlevel, while those beginning with an S are started

Init process PID is 1

Running Additional Programs at Boot Time :

The /etc/rc.d/rc.local script is executed by the init command at boot time or when changing runlevels. Adding commands to the bottom of this script is an easy way to perform necessary tasks like starting special services or initialize devices without writing complex initialization scripts in the /etc/rc.d/init.d/ directory and creating symbolic links.

SysV Init Runlevels :

The SysV init runlevel system provides a standard process for controlling which programs init launches or halts when initializing a runlevel. SysV init was chosen because it is easier to use and more flexible than the traditional BSD-style init process.

Run levels in Linux

The following runlevels are defined by default under Red Hat Enterprise Linux:

  • 0 — Halt
  • 1 — Single-user text mode
  • 2 — Not used (user-definable)
  • 3 — Full multi-user text mode
  • 4 — Not used (user-definable)
  • 5 — Full multi-user graphical mode (with an X-based login screen)
  • 6 — Reboot

How to define default run level:

Edit the /etc/inittab:

id:5:initdefault:

Runlevel Utilities

One of the best ways to configure runlevels is to use an initscript utility. These tools are designed to simplify the task of maintaining files in the SysV init directory hierarchy and relieves system administrators from having to directly manipulate the numerous symbolic links in the subdirectories of /etc/rc.d/.

Red Hat Enterprise Linux provides three such utilities:

  • /sbin/chkconfig — The /sbin/chkconfig utility is a simple command line tool for maintaining the /etc/rc.d/init.d/ directory hierarchy.
  • /usr/sbin/ntsysv — The ncurses-based /sbin/ntsysv utility provides an interactive text-based interface, which some find easier to use than chkconfig.
  • Services Configuration Tool — The graphical Services Configuration Tool (system-config-services) program is a flexible utility for configuring runlevels.