Docker Introduction and Practice

How It Works

Docker is an operating-system-level virtualization technology. Its isolated processes are independent of the host and other isolated processes, and are also called containers.

How Docker differs from traditional virtualization

Simply put, Docker does not virtualize hardware. It runs directly on the host kernel, making it lighter and more efficient.

  • Comparison with traditional virtual machines

Basic Concepts

  • Image: A Docker image is a special filesystem. Besides the programs, libraries, resources, configuration files, and other files needed to run a container, it contains runtime configuration parameters such as anonymous volumes, environment variables, and users. Docker images are stored in layers, allowing new functionality to be added layer by layer on top of an original image.
  • Container: A running instance of an image. Essentially, it is a process with its own command space, isolated from other processes. Its storage layer is also created dynamically and disappears when the container is removed. Data is generally persisted by binding a data volume.
  • Repository: A place to store and distribute images.

Installation

# 卸载旧的版本
$ sudo apt-get remove docker \
               docker-engine \
               docker.io

# 安装依赖
$ sudo apt-get update

$ sudo apt-get install \
     apt-transport-https \
     ca-certificates \
     curl \
     gnupg-agent \
     lsb-release \
     software-properties-common
# 换源加速
## 添加GPG密钥
$ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo apt-key add -


# 官方源
# $ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

# 添加docker 软件源
$ sudo add-apt-repository \
   "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/debian \
   $(lsb_release -cs) \
   stable"

# 官方源
# $ sudo add-apt-repository \
#    "deb [arch=amd64] https://download.docker.com/linux/debian \
#    $(lsb_release -cs) \
#    stable"

# 安装 docker
$ sudo apt update

$ sudo apt install docker-ce docker-ce-cli containerd.io

# 启动docker
$ sudo systemctl enable docker
$ sudo systemctl start docker

# 建立docker组
$ sudo groupadd docker

# 将当前用户加入docker组
$ sudo usermod -aG docker $USER

# 测试Docker是否安装正确
sudo docker run hello-world

Basic Commands

  • Pull an image
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
  • Run a container

  • List images

  • Remove an image

$ docker image rm [选项] <镜像1> [<镜像2> ...]

Writing a Dockerfile

Like a MakeFile, a Dockerfile consists of instructions describing how the final image is built.

A Simple Example

$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile

# Dockerfile内容
FROM nginx
RUN echo '<h1> Hello ,Docker!</h1>' > /usr/share/nginx/html/index.html

## FROM 指定基础镜像, 如果从空白镜像开始,则可以使用scratch
## RUN 执行命令,一个RUN就会新建一层,而Union FS是有层数的限制的,大概在127层,
## 对于没有必要新建一层的操作,一般直接用 && 连接命令

# 构建的命令
$ docker build -t nginx:v3 .

Image Build Context

Docker runs in a client/server model. When you execute docker build -t ., the Docker client packages all files in the . directory and sends them to the Docker engine on the server. This is why an empty directory or the project’s root directory is generally chosen when building an image. File operations in the DockerFile, such as COPY, should specify file locations relative to the current directory (or root directory), for example ./config.json. With paths such as /opt/xxx or ../config.json, the Docker engine cannot find the corresponding files, causing the build to fail.

Other Uses of docker duild

  • Build directly from a Git repository: docker build -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world
  • Build from a given tar archive: docker build http://server/context.tar.gz
  • Build by reading a DockerFile from standard input: docker build - < Dockerfile
  • Build by reading a compressed context archive from standard input: ` docker build - < context.tar.gz`

Dockerfile Instructions in Detail

COPY
# 格式
COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
## 例子
COPY package.json /usr/src/app/
COPY --chown=55:mygroup files* /mydir/
COPY --chown=bin files* /mydir/
COPY --chown=1 files* /mydir/
COPY --chown=10:11 files* /mydir/
ADD
# 格式同COPY, 功能更强,源路径可以是URL,默认权限600,会自动解压,
# 一般用来添加初始的官方镜像,eg
FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
# 在其他的情况下推荐使用语义更明确的COPY
CMD
# shell 格式 : CMD <命令>
# exec 格式: CMD ["可执行文件", "参数1", "参数2" ...]
# 推荐使用exec格式, 实际shell格式的最终也会被解析成sh -c
# 如 CMD echo $HOME
CMD ["sh", "-c", "echo $HOME"]
# 另外容器即是进程,没有后台服务的概念
# eg
CMD service nginx start
# 会被解析成
CMD ["sh", "-c", "service nginx start"]
# 命令执行结束,sh也结束了,容器就会退出
# 正确的方式如下
CMD ["nginx", "-g", "daemon 0ff;"]
Other Instructions
# ENTERPOINT 入口点
# ENV 设置环境变量
# ARG 构建参数
# VOLUME 定义匿名卷
# EXPOSE 暴露端口
# WORKDIR 指定工作目录
# USER指定当前用户
# 等

Usage

Container Operations

# 启动
# docker run
docker run ubuntu:18.04 /bin/bash 'hello world'
docker run -it ubuntu:18.04 /bin/bash
# docker start
# 先通过docker container ls -a 查看已经终止的容器
# 再用docker start [container ID or name]使其继续运行
# 守护态运行
# docker run -d 
# 可以将STDOUT从定向到logs中
# 然后通过docker container logs [container ID or NAMES]
# 就可以看到相关输出
# 终止
docker container stop [container ID or NAMES]
# 进入容器
# 使用docker exec 可以进入-d在守护态运行的容器
# 并且exit不会导致容器停止,docker attach 会
docker exec -i example-container bash
docker exec -it example-container bash
# 删除
# 删除特定的容器
docker container rm [container ID or NAMES]
# 删除所有已经终止的容器
docker container prune

Data Management

# 数据卷
## 创建一个数据卷
docker volume create my-vol
## 查看数据卷
docker volume ls
## 查看数据卷的具体信息
docker volume inspect my-vol
## 启动一个挂载数据卷的容器
docker run -d -P --name web \
--mount source=my-vol,target=/usr/share/nginx/html\
nginx:alpine
## 删除数据卷
docker colume rm my-vol
## 删除未被使用的数据卷
# 挂载主机目录
docker run -d -P \
--name web \
--mount type=bind,source=/src/webapp,

Networking