docker

1 容器技术基础入门

1.1 Container

Container

  • 容器是一种基础工具;泛指任何可以用于容纳其他物品的工具,可以部分或完全封闭,被用于容纳、储存、运输物品;物体可以被放置在容器中,而容器则可以保护内容物;
  • 人类使用容器的历史至少有十万年,甚至可能有数百万年的历史;
  • 容器的类型
    • 瓶 - 指口部比腹部窄小、颈长的容器。
    • 罐 - 指那些开口较大、一般为近圆筒形的器皿。
    • 箱 - 通常是立方体或圆柱体。形状固定。
    • 蓝 - 以条状物编织而成。
    • 桶 - 一种圆柱形的容器
    • 袋 - 柔性材料制成的容器,形状会受内容物而变化。
    • 瓮 - 通常是指陶制,口小肚大的容器。
    • 碗 - 用来盛载食物的容器。
    • 柜 - 指一个由盒组成的家具。
    • 鞘 - 用于装载刀刃的容器。

1.2 LXC(LinuX Container)

1.3 虚拟化和容器之间的关系

Virtualization and Container

虚拟化的常用实现形式

  • 主机级虚拟化:虚拟的是整个物理硬件平台;如:vmware workstation
    • Type-I:物理硬件平台之上安装一个虚拟机管理器,通常叫做hypervisor,然后hupervisor之上安装使用虚拟机
    • Type-II:物理硬件平台之上安装一个主机操作系统(hostOS),称为宿主机操作系统,在宿主机之上安装一个VMM(Virtual Machine Manager),VMM之上再创建使用虚拟机。在如:vmware workstation、virtualbox
  • 容器级虚拟化

1.4 Linux Namespaces and CGroups

1.4.1 Namespaces

  • Namespaces
    • Mount namespaces:挂载点
    • UTS namespaces:主机名与域名
    • IPC namespaces:信号量、消息队列和共享内存
    • PID namespaces:进程号
    • Network namespaces:网络设备、网络线、端口等
    • User namespaces:用户和组
1.4.2 Control Groups(cgroups)
  • cgroups
    • blkio:块设备IO
    • cpu:CPU
    • cpuacct:CPU资源使用报告
    • cpuset:多处理器平台上的CPU集合
    • devices:设备访问
    • freezer:挂起或恢复任务
    • memory:内存用量及报告
    • perf_event:对cgroup中的任务进行统一性能测试
    • net_cls:cgroup中的任务创建的数据报文的类型标识符

2 Docker 初识

2.1 What is docker

docker这个单词指:码头工人

  • docker中的容器
    • lxc -> libcontainer -> runC

      要想使用 LXC,至少要在 Linux 内核级支持两种技术:1.namespace 2.cgroups

2.2 docker 分层构建镜像

docker提供了镜像,而且是分层构建的镜像的方式,使得容器的使用更加简化。
后来,在docker主导下就有了 OCI 和 OCF 的标准

docker容器站点:https://hub.docker.com
比如搜索 nginx 可以找到提供的 nginx 的镜像

2.3 docker architecture


docker 可以认为是 C/S 架构的应用程序,不管是 Client 还是 Server,都由docker一个程序提供。这个程序有很多子命令,运行 docker daemon 就表示把这台主机变成守护进程服务器,它可以监听在某个套接字之上。为了安全,这个套接字默认只提供本机的 Unix Sock 文件的套接字。

  • Client:
    • 与 DOCKER_HOST 端通信使用的是 http/https 协议
  • DOCKER_HOST:docker的API也是RESTFUL风格
    • Containers:基于下载的只读镜像创建可以修改的镜像
    • Images:本地镜像仓库;下载镜像到本地镜像仓库时使用的是 http/https 协议,默认是https
  • Registry:docker的镜像仓库,默认到 dockerhub 下载镜像;有几十万个镜像

2.4 docker 版本

docker 版本

  • Moby:docker 商业版
  • docker-ee:docker 企业版
  • docker-ce:docker 社区版

2.5 Docker objects

2.6 Docker Host and Registry

2.7 Docker 编排工具

Docker 编排工具:

  • machine+swarm+compose

    docker compose:它适用于单机编排;

    为了对多个 docker host 进行调度实现集群的效果,docker 后来又提供了另外一款工具: docker swarm,它是能够将多个 docker host 整合为同一平台之下的管理机制的集群工具,能够将多个 docker host 提供的计算资源整合为一个资源池,而后 docker compose 编排时,只需要面对 swarm 整合出来的资源池进行编排就行,而不用管 docker host 的情况。

    而 swarm 也只是 docker 自身的应用程序,那么每一个主机从开始的时候怎么去安装成为 docker 主机呢?就需要另外一款工具:docker machine,能够将一个主机迅速初始化为 swarm 集群中的成员主机。

  • mesos+marathon

    mesos 是 IDC 的操作系统,能够把一个 IDC 当中的所有硬件所提供的计算资源统一调度和分配,但是它所面向的上层接口所提供的不是容器运行的接口,而只是资源分配工具,不能直接托管运行容器。所以在此基础之上,必须要提供一个面向容器编排的框架,叫做marathon

  • kubernetes -> k8s

3 安装及使用docker

3.1 安装 docker

范例:

docker社区版repo源下载到本地:
# wget https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo

替换 docker-ce.repo 中的 baseurl:
https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/7/x86_64/stable/Packages/

安装 docker-ce:
# yum install docker-ce

3.2 docker 配置文件

配置文件:/etc/docker/daemon.json

3.3 docker 镜像加速

  • docker cn
  • 阿里云加速器
  • 中国科技大学

范例:

添加镜像加速器:
在 docker 配置文件 daemon.json (初始该文件不存在)中添加:
{
"registry-mirrors":["https://fdzsr0bg.mirror.aliyuncs.com","https://registry.docker-cn.com"]
}

3.6 启动 docker 服务

启动 docker 服务
systemctl start docker.service

3.7 docker 相关命令

3.7.1 查看子命令

查看子命令:# docker

3.7.2 查看docker环境信息

查看 docker 环境信息:docker version

[root@node1 ~]# docker version
Client: Docker Engine - Community
 Version:           20.10.6
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        370c289
 Built:             Fri Apr  9 22:45:33 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.6
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       8728dd2
  Built:            Fri Apr  9 22:43:57 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.4
  GitCommit:        05f951a3781f4f2c1911b05e61c160e9c30eaa8e
 runc:
  Version:          1.0.0-rc93
  GitCommit:        12644e614e25b05da6fd08a38ffa0cfe1903fdec
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

查看更详细的docker环境信息:docker info

[root@node1 ~]# docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
  buildx: Build with BuildKit (Docker Inc., v0.5.1-docker)
  scan: Docker Scan (Docker Inc.)

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 20.10.6
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e
 runc version: 12644e614e25b05da6fd08a38ffa0cfe1903fdec
 init version: de40ad0
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 5.12.0-1.el7.elrepo.x86_64
 Operating System: CentOS Linux 7 (Core)
 OSType: linux
 Architecture: x86_64
 CPUs: 1
 Total Memory: 979.4MiB
 Name: node1.ckh.com
 ID: L27U:ULW4:E5RK:SL5B:66M2:4XGR:S7CX:BHJU:LR4C:L6TZ:YSJF:SOWM
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Registry Mirrors:
  https://registry.docker-cn.com/
 Live Restore Enabled: false
3.7.3 docker 常用操作

docker 常用操作

  • docker search:Search the Docker Hub for images
  • docker pull:Pull an image or a repository from a registry,可使用docker image pull命令代替
  • docker images:List images,可使用docker image ls命令代替
  • docker rmi:Remore one or more images,可使用docker image rm命令代替
  • docker create:Create a new container
  • docker start:Start one or more stopped containers
  • docker run:Run a command in a new container
  • docker attach:Attach to a running container
  • docker ps:List containers
  • docker logs:Fetch the logs of a container
  • docker restart:Restart a container
  • docker stop:Stop one or more running containers
  • docker kill:Kill one or more running containers
  • docker rm:Remove one or more containers

范例:

[root@node1 ~]# docker search nginx
NAME                               DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
nginx                              Official build of Nginx.                         14849     [OK]      ##顶级仓库中的镜像,docker hub官方的镜像
jwilder/nginx-proxy                Automated Nginx reverse proxy for docker   
con…   2027                 [OK]    #### 用户自定义仓库镜像
richarvey/nginx-php-fpm            Container running Nginx + PHP-FPM capable of…   813                  [OK]
jc21/nginx-proxy-manager           Docker container for managing Nginx proxy ho…   186

[root@node1 ~]# docker image pull nginx:1.14-alpine
1.14-alpine: Pulling from library/nginx
bdf0201b3a05: Pull complete
3d0a573c81ed: Pull complete
8129faeb2eb6: Pull complete
3dc99f571daf: Pull complete
Digest: sha256:485b610fefec7ff6c463ced9623314a04ed67e3945b9c08d7e53a47f6d108dc7
Status: Downloaded newer image for nginx:1.14-alpine
docker.io/library/nginx:1.14-alpine

[root@node1 ~]# docker pull busybox:latest
latest: Pulling from library/busybox
aa2a8d90b84c: Pull complete
Digest: sha256:be4684e4004560b2cd1f12148b7120b0ea69c385bcc9b12a637537a2c60f97fb
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest

[root@node1 ~]# docker image ls
REPOSITORY   TAG           IMAGE ID       CREATED       SIZE
busybox      latest        c55b0f125dc6   8 days ago    1.24MB
nginx        1.14-alpine   8a2fb25a19f5   2 years ago   16MB

[root@node1 ~]# docker image ls --no-trunc
REPOSITORY   TAG           IMAGE ID                                                                  CREATED       SIZE
busybox      latest        sha256:c55b0f125dc65ee6a9a78307d9a2dfc446e96af7477ca29ddd4945fd398cc698   9 days ago    1.24MB
nginx        1.14-alpine   sha256:8a2fb25a19f5dc1528b7a3fabe8b3145ff57fe10e4f1edac6c718a3cf4aa4b73   2 years ago   16MB

范例:

创建并运行一个容器:
[root@node1 ~]# docker run --name b1 -it busybox:latest 
[root@node1 ~]# docker run --name web1 -d nginx:1.14-alpine   # nginx启动为守护进程
[root@node1 ~]# docker run --name kvstor1 -d redis:3.4-alpine  # redis启动为守护进程

busybox 中手动运行 httpd服务:
# httpd -f -h /data/html  #在容器内创建 /data/html/index.html
# ps

查看启动的容器
[root@node1 ~]# # docker container ls
CONTAINER ID   IMAGE               COMMAND                  CREATED          STATUS          PORTS      NAMES
c7ed35045ff1   redis:4-alpine      "docker-entrypoint.s…"   19 minutes ago   Up 19 minutes   6379/tcp   kvstor1
ffd1b81ab6e9   nginx:1.14-alpine   "nginx -g 'daemon of…"   27 minutes ago   Up 27 minutes   80/tcp     web1

查看容器内运行的服务状态信息:docker inspect
[root@node1 ~]# docker inspect web1

停止容器:docker stop|kill 
[root@node1 ~]# # docker container stop b1
[root@node1 ~]# # docker container kill b1
删除容器:docker rmi
[root@node1 ~]# # docker container rm b1

启动容器---> # docker start|restart
# httpd [root@docker start -ai b1

不进入容器执行命令:# docker exec
[root@node1 ~]# docker exec -it kvstor1 /bin/sh
3.7.4 docker event state

4 Docker images

docker镜像 是能够启动docker容器的一个非常重要的组件。

4.1 About Docker Images

  • Docker镜像含有启动容器所需要的文件系统及其内容,因此,其用于创建并启动docker容器
    • 采用分层构建机制,最底层为bootfs,其之上为rootfs
      • bootfs:用于系统引导的文件系统,包括bootloader和kernel,容器启动完成后会被卸载以节约内存资源;
      • rootfs:位于bootfs之上,表现为docker容器的根文件系统;
        • 传统模式中,系统启动时,内核挂载rootfs时会首先将其挂在为”只读“模式,完整性自检完成后将其重新挂载为读写模式;
        • docker中,rootfs由内核挂载为"只读"模式,而后通过”联合挂载“技术额外挂载一个”可写“层

4.2 Docker Image Layer

  • 位于下层的镜像称为父镜像(parent image),最底层的称为基础镜像(base image)
  • 最上层为"可读写"层,其下的均为"只读"层

4.3 Aufs

  • advanced multi-layered unification filesystem:高级多层统一文件系统
  • 用于为Linux文件系统实现"联合挂载"
  • aufs是之前的UnionFS的重新实现,2006年由Junjiro Okajima开发
  • Docker最初使用aufs作为容器文件系统层,它目前仍作为存储后端之一来支持
  • aufs的竞争产品是overlayfs,后者自从3.18版本开始被合并到Linux内核
  • docker的分层镜像,除了aufs,docker还支持btrfs,devicemapper和vfs等
    • 在Ubuntu系统下,docker默认Ubuntu的aufs;而在CentOS7上,用的是devicemapper

4.4 Devicemapper

  • Device Mapper 是 Linux2.6 内核中支持逻辑卷管理的通用设备映射机制,它为实现用于存储资源管理的块设备驱动提供了一个高度模块化的内核架构

在内核中它通过一个一个模块化的 target driver 插件实现对 IO 请求的过滤或者重新定向等工作,当前已经实现的 target driver 插件包括软raid、软加密、逻辑卷条带、多路径、镜像、快照等

  • 前一页图中 linear、mirror、snapshot、multipath 表示的就是这些 target driver
  • 在这诸多”插件“中,有一种叫Thin Provisioning Snapshot,Docker正是使用了 Thin Provisioning 的Snapshot的技术实现了类似auFS的分层镜像

4.5 Docker Registry

4.5.1 Docker Registry 工作过程
  • 启动容器时,docker daemon会试图从本地获取相关的镜像;本地镜像不存在时,其将从Registry中下载该镜像并保存到本地
    • The Registry is a stateless,highly scalable server side application that stores and lets you distribute Docker images
4.5.2 Docker Registry 分类
  • Registry用于保存docker镜像,包括镜像的层次结构和元数据
  • 用户可自建Registry,也可使用官方的Docker Hub
  • 分类
    • Sponsor Registry:第三方的registry,供客户和Docker社区使用
    • Mirror Registry:第三方的registry,只让客户使用
    • Vendor Registry:由发布Docker镜像的供应商提供的registry
    • Private Registry:通过设有防火墙和额外的安全层的私有实体提供的registry
4.5.3 Registry组成(repository and index)

Registry 有两部分组成

  • Repository
    • 由某特定的docker镜像的所有迭代版本组成的镜像仓库
    • 一个Registry钟可以存在多个Repository
      • Repository可分为"顶层仓库"和"用户仓库"
      • 用户仓库名称格式为"用户名/仓库名"
    • 每个仓库可以包含多个Tag(标签),每个标签对应一个镜像
  • Index
    • 维护用户账户、镜像的校验以及公共命名空间的信息
    • 相当于为Registry提供了一个完成用户认证等功能的检索接口
4.5.4 Docker Registry 来源
  • Docker Registry中的镜像通常由开发人员制作,而后推送至"公共"或"私有"Registry上保存,供其他人员使用,例如"部署"到生成环境
4.5.6 Docker Hub
  • Docker Hub is a cloud-based registry service which allows you to link to code repositories,build your images and test them,stores manually pushed images,and links to Docker Cloud so you can deploy images to your hosts.

  • It provides a centralized resource for container image discovery,distribution and change management,user and team collaboration,and workflow automation throughout the development pipeline.

  • Docker Hub provides the following major fetures

  • Image Repositories

    • Find and pull images from community and offcial libraries,and manage,push to,and pull from private image libraries to which you have access.
    • Automated Builds
      • Automatically create new images when you make changes to a source code repository
    • Webhooks
      • A feature of Automated Builds,Webhooks let you trigger actions after a successful push to a repository.
    • Organizations
      • Create work groups to manage access to image repositories.
    • GitHub and Bitbucket Integration
      • Add the Hub and your Docker Images to your current workflows.
4.5.7 Getting images from remote Docker registries
  • To get Docker images from a remote registry (such as your own Docker registry) and add them to your local system,use the docker pull command;
    docker pull <registry>[:<port>]/[<namespace>/]<name>:<tag>
  • The <registry> is a host that provides the docker-distribution service on TCP <port>(default:5000)
  • Together,<namespace> and <name> identify a particular image controlled by <namespace> at that registry
    • Some registries also support raw <name>;for those,<namespace> is optional
    • When it is included,hower,the additional level of hierarchy that <namespace> provides is userful to distinguish between images with the same <name>

范例:

范例:

[root@node1 tmp]# docker pull quay.io/coreos/flannel:v0.10.0-amd64
v0.10.0-amd64: Pulling from coreos/flannel
ff3a5c916c92: Pull complete
8a8433d1d437: Pull complete
306dc0ee491a: Pull complete
856cbd0b7b9c: Pull complete
af6d1e4decc6: Pull complete
Digest: sha256:88f2b4d96fae34bfff3d46293f7f18d1f9f3ca026b4a4d288f28347fcb6580ac
Status: Downloaded newer image for quay.io/coreos/flannel:v0.10.0-amd64
quay.io/coreos/flannel:v0.10.0-amd64

The additional level of hierarchy of <namespace>

4.6 镜像相关操作

4.6.1 镜像的生成途径
  • Dockerfile
  • 基于容器制作
  • Docker Hub automated builds
4.6.2 基于容器制作镜像
  • Create a new image from a container's changes
  • Usage
    • docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG:]]

使用示例:

为镜像设定标签

  • docker tag
    • Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
    • Syntax
      • docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
    • 示例

下面是一个完整示例:

查看已经存在的容器:

[root@node1 tmp]# docker container ls
CONTAINER ID   IMAGE               COMMAND                  CREATED          STATUS          PORTS      NAMES
02aa747b09df   busybox             "sh"                     21 minutes ago   Up 17 minutes              b1

基于 b1 容器提交镜像:

[root@node1 tmp]# docker commit -p  b1sha256:147bedfe0c727afcda1d37fc9331b171c8c3c5cb0ca9e53ce3dc8fa6208fe6d6[root@node1 tmp]# docker image lsREPOSITORY               TAG             IMAGE ID       CREATED         SIZE<none>                   <none>          147bedfe0c72   9 seconds ago   1.24MB

对提交的镜像打上标签tag:

[root@node1 ~]# docker tag 4b4db2281523 chengkh/httpd:v0.1[root@node1 ~]# docker image lsREPOSITORY               TAG             IMAGE ID       CREATED         SIZEchengkh/httpd            v0.1            4b4db2281523   3 hours ago     1.24MB

对已打标签的镜像再打标签:

[root@node1 ~]# docker tag chengkh/httpd:v0.1 chengkh/httpd:latest[root@node1 ~]# docker image lsREPOSITORY               TAG             IMAGE ID       CREATED         SIZEchengkh/httpd            latest          4b4db2281523   3 hours ago     1.24MBchengkh/httpd            v0.1            4b4db2281523   3 hours ago     1.24MB

删除对已有标签再打标签的镜像

[root@node1 tmp]# docker image rm chengkh/httpd:latestUntagged: chengkh/httpd:latest

提交镜像,修改默认运行的命令:

[root@node1 ~]# docker container commit -a "chengkh <chengkh1989@gmail.com>" -c 'CMD ["/bin/httpd","-f","-h","/data/html"]' -p b1 chengkh1989/httpd:v0.2sha256:c333614f7466c9a2263580c1cd3cd9e6b698b1d48c02a4469867eeb48e5c51e2

基于 chengkh/httpd:v0.2 镜像运行一个容器:

[root@node1 ~]# docker container run --name test3 chengkh1989/httpd:v0.2

访问容器中的服务:

[root@node1 ~]# docker inspect t2 "IPAddress": "172.17.0.5",[root@node1 ~]# curl 172.17.0.5<h1>Busybox httpd server.</h1>
4.6.2.1 将镜像push到Docker Hub
  • docker push

    • Push images to Docker Cloud or private registry
    • 推送镜像到Docker Hub的前提是在Docker Hub已有用户账号,且镜像标签格式为"$DOCKER_USER_ID/IMAGE"
    • 使用docker login命令登录成功后,即可使用docker push命令进行推送
    • 示例
      • ~]# docker push chengkh1989/httpd:version0.1
  • Docker Hub地址:https://hub.docker.com/repositories

    • 账号:chengkh1989@gmail.com
    • 密码:CKH123456
    • registry 密码:CKH123456

下面是一个push示例:

首先执行 docker login 命令

Usage:  docker login [OPTIONS] [SERVER]Log in to a Docker registry.If no server is specified, the default is defined by the daemon.Options:  -p, --password string   Password      --password-stdin    Take the password from stdin  -u, --username string   Username

范例:

[root@node1 ~]# docker login -u chengkh1989Password:CKH123456WARNING! Your password will be stored unencrypted in /root/.docker/config.json.Configure a credential helper to remove this warning. Seehttps://docs.docker.com/engine/reference/commandline/login/#credentials-storeLogin Succeeded

docker push 镜像:

Usage:  docker push [OPTIONS] NAME[:TAG]Push an image or a repository to a registryOptions:  -a, --all-tags                Push all tagged images in the repository      --disable-content-trust   Skip image signing (default true)  -q, --quiet                   Suppress verbose output

范例:

[root@node1 ~]# docker push chengkh1989/httpd:v0.2The push refers to repository [docker.io/chengkh1989/httpd]a25807387df4: Pushed36b45d63da70: Mounted from library/busyboxv0.2: digest: sha256:27a0b102369976d29d344a3a856bddd27d014e4e85d3134636ea187b9ee0992d size: 734
4.6.2.2 将镜像push到阿里云仓库
  • 阿里云地址:https://cr.console.aliyun.com/cn-hangzhou/instances
    • 账号:chengkaihua89
    • 密码:CKH123456
    • registry 密码:CKH123456

范例:
[root@node1 ~]# docker tag chengkh1989/httpd:v0.2 registry.cn-hangzhou.aliyuncs.com/chengkh1989/httpd:v0.2

[root@node1 ~]# docker login --username=chengkaihua89 registry.cn-hangzhou.aliyuncs.com
Password: CKH123456

[root@node1 ~]# docker push registry.cn-hangzhou.aliyuncs.com/chengkh1989/httpd:v0.2

4.6.2.3 镜像导入和导出
  • docker save

    • Save one or more images to a tar archive (streamed to STDOUT by default)
    • Usage:docker save [OPTIONS] IMAGE [IMAGE...]
      • --output,-o:Write to a file,instead of STDOUT
  • docker load

    • Load an image from a tar archive or STDIN
    • Usage:docker load [OPTIONS]
      • --input,-i:Read from tar archive file,instead of STDIN
      • --quiet,-q:Suppress the load output

范例:

[root@node1 ~]# docker save -o myimages.gz chengkh1989/httpd:v0.2 registry.cn-hangzhou.aliyuncs.com/chengkh1989/httpd:v0.2[root@node1 ~]# docker load -i myimages.gz

5 Docker Networking

5.1 docker网络概述

5.2 docker网络类型

docker 支持的四种网络模型:
s 58

5.2.1 Bridged containers
  • 桥接式容器一般拥有两个接口:一个回环接口和一个连接至主机上某桥设备的以太网接口
  • docker daemon 启动时默认会创建一个名为 docker0 的网络桥,并且创建的容器为桥接式容器,其以太网接口桥接至docker0
    • --net bridge即为将容器接口添加至docker0桥
  • docker0桥为 NAT 桥,因此,桥接式容器可通过此桥接接口访问外部网络,但防火墙规则阻止了一切从外部网络访问桥接式容器的请求
    • ~]# docker run --name c1 -it --network bridge --rm busybox:latest
5.2.2 Closed containers
  • 不参与网络通信,运行于此类容器中的进程仅能访问本地回环接口
  • 仅适用于进程无须网络通信的场景中,例如备份、进程诊断及各种离线任务等
    • ~]# docker run --name c1 -it --network none --rm busybox:latest
5.2.3 docker run 命令使用
  • 可以为docker run 命令使用
    • "--hostname HOSTNAME"选项为容器指定主机名
    • "--dns DNS_SERVER_IP"选项能够为容器指定所使用的dns服务器地址,"--dns-search"为容器dns解析时添加默认后缀
    • "--add-host HOSTNAME:IP"选项能够为容器指定本地主机名解析项

范例:

[root@node1 ~]# docker run --name c1 -it --network bridge --hostname c1.ckh.com  --dns 114.114.114.114 --dns-search ilinux.io --add-host www.ckh.com:1.1.1.1 --rm busybox:latest

5.2.4 Opening inbound communication

  • Docker0为NAT桥,因此容器一般获得的是私有网络地址

  • 可以把容器想象为宿主机NAT服务背后的主机

  • 如果开放容器或其上的服务为外部网络访问,需要在宿主机上为其定义DNAT规则,例如

    • 对宿主机某IP地址的访问全部映射给某容器地址
      • 主机IP 容器IP
        • -A PREROUTING -d 主机IP -j DNAT --to-destination 容器IP
    • 对宿主机某IP地址的某端口的访问映射给某容器地址的某端口
      • 主机IP:PORT 容器IP:PORT
        • -A PREROUTING -d 主机IP -p {tcp|udp} --dport 主机端口 -j DNAT --to-destination 容器IP:容器端口
  • 为 docker run 命令使用 -p 选项即可实现端口映射,无须手动添加

    • -p选项的使用格式
      • -p <containerPort>

        • 将指定的容器端口映射至主机所有地址的一个动态端口
      • -p <hostPort>:<containerPort>

        • 将容器端口<containerPort>映射至指定的主机端口<hostPort>
      • -p <ip>::<containerPort>

        • 将指定的容器端口<containerPort>映射至主机指定<ip>的动态端口
      • -p <ip>:<hostPort>:<containerPort>

        • 将指定的容器端口<containerPort>映射至主机指定<ip>的端口<hostPort>
      • "动态端口"指随机端口,具体的映射结果可使用 docker port 命令查看

范例:

[root@node1 ~]# docker run --name myweb --rm -p 80 chengkh1989/httpd:v0.2[root@node1 ~]# docker port myweb80/tcp -> 0.0.0.0:4915680/tcp -> :::49156[root@node1 ~]# docker run --name myweb --rm -p 3503:80 chengkh1989/httpd:v0.2[root@node1 ~]# docker port myweb80/tcp -> 0.0.0.0:350380/tcp -> :::3503[root@node1 ~]# docker run --name myweb --rm -p 192.168.2.11::80 chengkh1989/httpd:v0.2[root@node1 ~]# docker port myweb80/tcp -> 192.168.2.11:49154   [root@node1 ~]# docker run --name myweb --rm -p 192.168.2.11:80:80 chengkh1989/httpd:v0.2[root@node1 ~]# docker port myweb80/tcp -> 192.168.2.11:80
  • "-P"选项或"--publish-all"将容器的所有计划要暴露端口全部映射至主机端口

  • 计划要暴露的端口使用--expose选项指定

    • 例如
      • ~]# docker run -d -P --expose 22222 --expose 3333 --name web busybox:latest /bin/httpd -p 2222 -f
      • 查看映射结果
        • ~]# docker port web
  • 如果不想使用默认的docker()桥接口,或者需要修改此桥接口的网络属性,可通过docker daemon命令使用-b、--bip、--fixed-cidr、--default-gateway、--dns以及--mtu等选项进行设定

5.2.5 Joined containers
  • 联盟式容器是指使用某个已存在容器的网络接口的容器,接口被联盟内的各容器共享使用;因此,联盟式容器彼此间完全无隔离,例如
    • 创建一个监听于2222端口的http服务容器
      • ~]# docker run -d -it --rm -p 2222 busybox:latest /bin/httpd -p 2222 -f
    • 创建一个联盟式容器,并查看其监听的端口
      • ~]# docker run -it --rm --net container:web --name joined busybox:latest netstat -tan
  • 联盟式容器彼此间虽然共享同一个网络名称空间,但其他名称空间如User、Mount等还是隔离的
  • 联盟式容器彼此间存在端口冲突的可能性,因此,通常只会在多个容器上的程序需要程序loopback接口互相通信、或对某已存在的容器的网络属性进行监控时才使用此种模式的网络模型
  • 联盟式容器就是两个名称空间各自使用独立的 USER,MOUNT,PID 名称空间,但共享 UTS,NET,IPC 名称空间。

范例:启动两个容器看看效果

创建并启动 b1 容器:[root@node1 ~]# docker run --name b1 -it --rm busybox创建并启动 b2 容器:[root@node1 ~]# docker run --name b2  --network container:b1  -it --rm busyboxb1:/ # echo "hello world" > /tmp/index.html/ # httpd -h /tmp// # netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address           Foreign Address         Statetcp        0      0 :::80                   :::*                    LISTENb2:wget -O - -q 127.0.0.1hello world不过在 b2 上是看不到 /tmp/index.html 文件的。这是否如果在 b2 上也启动 httpd 服务会有什么效果:/ # echo "hello b2" > /tmp/index.html/ # httpd -h /tmp/httpd: bind: Address already in use

第四种网路模型:基于host创建容器

[root@node1 ~]# docker run --name b3 --rm -it --network host busybox
/ # echo "hello container " > /tmp/index.html
/ # httpd -h /tmp/
s 63

5.2.6 自定义 docker0 桥的网络属性信息
5.2.6.1 修改容器启动时的默认 ip 地址

cat /etc/docker/daemon.json

{    "bip": "192.168.1.5/24",    "fixed-cidr": "10.20.0.0/16",    "fixed-cidr-v6": "2001:db8::/64",    "mtu": 1500,    "default-gateway": "10.20.1.1",    "default-gateway-v6": "2001:db8:abc::89",    "dns": ["10.20.1.2","10.20.1.3"]}

核心选项为 bip,即 bridge ip 之意,用于指定docker0桥自身的IP地址;其他选项可通过此地址计算得出。

5.2.6.2 远程连接其他主机上的 docker

dockerd 守护进程的 C/S,其默认仅监听Unix SOcket格式的地址,/var/run/docker.sock;如果使用TCP套接字:
/etc/docker/daemon.json:

"hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]

客户端(192.168.2.12)远程连接docker:
docker -H 192.168.2.11:2375 image ls

5.2.6.3 创建自定义的桥

创建自定义桥

docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" mybr0

自定义桥改名

ip link set dev br-af4bb91c0969 name docker1

在自定义桥上创建一个容器 t1:

docker run --name t1 -it --net mybr0  busybox:latest

宿主机的 bridge 桥上创建容器 t2:

docker run --name t2 -it --net bridge busybox:latest

此时打开宿主机的核心转发功能,iptables 规则不阻止的话, t1 和 t2 是可以互相通信的。

6 Docker Data Volume

6.1 Why Data Volumes?

  • Docker 镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层
  • 如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,此即"写时复制(COW)"机制

s 66

  • 关闭并重启容器,其数据不受影响;但删除Docker容器,则其更改将会全部丢失

  • 存在的问题

    • 存储于联合文件系统中,不易于宿主机访问;
    • 容器间数据共享不便
    • 删除容器其数据会丢失
  • 解决方案:“卷(volume)”

    • “卷”是容器上的一个或多个"目录",此类目录可绕过联合文件系统,与宿主机上的某目录“绑定(关联)”

s 67

6.2 Data volumes

  • Data volumes provide serveral useful features for persistent or shared data

    • Volume 于容器初始化之时即会创建,由base image提供的卷中的数据会于此期间完成复制
    • Data volumes can be shared and reused among containers
    • Changes to a data volume are made directly
    • Changes to a data volume will not be included when you update an image
    • Data volumes persist even if the container itself is deleted
  • Vlume 的初衷是独立于容器的生命周期实现数据持久化,因此删除容器之时既不会删除卷,也不会对哪怕未被引用的卷做垃圾回收操作;

  • 卷为docker提供了独立于容器的数据管理机制

    • 可以把“镜像”想象成静态文件,例如“程序”,把卷类比为动态内容,例如“数据”;于是,镜像可以重用,而卷可以共享;
    • 卷实现了“程序(镜像)”和“数据(卷)分离”,以及“程序(镜像)”和“制作镜像的主机”分离,用户制作镜像时无须再考虑镜像运行的容器所在的主机的环境;

s 68

6.3 Volume types

  • Docker 有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上的位置有所不同;

    • Bind mount volume

      • a volume that points to a tuser — specified location on the host file system
    • Docker-managed volume

      • the Docker daemon creates managed volumes in a portion of the host's file system that's owned by Docker

s 69

6.4 在容器中使用Volumes

  • 为 docker run 命令使用 -v 选项即可使用 Volume

    • Docker - managed volume

      • ~]# docker run -it -name bbox1 -v /data busybox
      • ~]# docker inspect -f {{.Mounts}} bbox1
        • 查看 bbox1 容器的卷、卷标识符及挂载的主机目录
    • Bind - mount Volume

      • ~]# docker run -it -v HOSTDIR:VOLUMEDIR --name bbox2 busybox

      • ~]# docker inspect -f {{.Mounts}} bbox2

范例:Docker - managed volume

[root@node1 ~]# docker run --name b1 -it --rm -v /data busybox/ # echo "hello world" > /data/test.html
 [root@node1 volumes]# docker inspect b1 "Mounts": [            {                "Type": "volume",                "Name": "99b6b23fa149622c01c0c46bac2e532ea3250bd5a33e0c59e6dc325534205825",                "Source": "/var/lib/docker/volumes/99b6b23fa149622c01c0c46bac2e532ea3250bd5a33e0c59e6dc325534205825/_data",                "Destination": "/data",                "Driver": "local",                "Mode": "",                "RW": true,                "Propagation": ""            }        ],"Config": {        "Volumes": {            "/data": {}        }, }
[root@node1 _data]# ls /var/lib/docker/volumes/99b6b23fa149622c01c0c46bac2e532ea3250bd5a33e0c59e6dc325534205825/_datatest.html

这时候如果执行删除容器操作,宿主机查看这个目录时:

[root@node1 _data]# ls /var/lib/docker/volumes/99b6b23fa149622c01c0c46bac2e532ea3250bd5a33e0c59e6dc325534205825/_datals: 无法访问/var/lib/docker/volumes/99b6b23fa149622c01c0c46bac2e532ea3250bd5a33e0c59e6dc325534205825/_data: 没有那个文件或目录

范例:Bind - mount Volume

[root@node1 ~]# docker run --name b2 -it --rm -v /data/volumes/b2:/var/lib/data busybox/ # echo "hello container" > /var/lib/data/test.html
   [root@node1 ~]# docker inspect b2   "Mounts": [            {                "Type": "bind",                "Source": "/data/volumes/b2",                "Destination": "/data",                "Mode": "",                "RW": true,                "Propagation": "rprivate"            }   "config": {   	 "Volumes": null,   }
[root@node1 ~]# cat /data/volumes/b2/test.htmlhello container

此时执行删除容器操作后,再次查看

[root@node1 ~]# cat /data/volumes/b2/test.htmlhello container
[root@node1 ~]# docker inspect -f {{.Mounts}} b2[{bind  /data/volumes/b2 /var/lib/data   true rprivate}]
[root@node1 ~]# docker inspect -f {{.NetworkSettings.Networks}} b2map[bridge:0xc00050db00]

6.5 Sharing volumes

  • There are tow ways to share volumes between containers

    • 多个容器的卷使用同一个主机目录,例如

      • ~]# docker run -it --name c1 -v /docker/volumes/v1:/data busybox
      • ~]# docker run -it --name c2 -v /docker/volues/v1:/data busybox
    • 复制使用其他容器的卷,为 docker run 命令使用 --volumes-from 选项

      • ~]# docker run -it --name bbox1 -v /docker/volumes/v1:/data busybox

      • ~]# docker run -it --name bbox2 --volumes-from bbox1 busybox

范例:多个容器的卷使用同一个主机目录

在 以上 b2 容器的基础上,我们另外再启动一个容器 b3,存储卷指向 b2 的存储卷

[root@node1 ~]# docker run --name b3 -it --rm -v /data/volumes/b2:/data busybox/ # echo "hello b3" >> /data/test.html
在 b2 容器上:/ # cat /var/lib/data/test.htmlhello containerhello b3

范例:复制使用其他容器的卷,为 docker run 命令使用 --volumes-from 选项

s 70

创建一个容器作为基础架构容器

[root@node1 ~]# docker run --name infracon -it -v /data/infracon/volume/:/data/web/html busybox

创建并启动nginx容器

[root@node1 ~]# docker run --name nginx --network container:infracon --volumes-from infracon -it busybox
[root@node1 ~]# docker inspect infracon

查看容器

"Mounts": [            {                "Type": "bind",                "Source": "/data/infracon/volume",                "Destination": "/data/web/html",                "Mode": "",                "RW": true,                "Propagation": "rprivate"            }        ],                "IPAddress": "10.0.0.2",
[root@node1 ~]# docker inspect nginx
    "Mounts": [            {                "Type": "bind",                "Source": "/data/infracon/volume",                "Destination": "/data/web/html",                "Mode": "",                "RW": true,                "Propagation": "rprivate"            }        ],

nginx容器中运行ifconfig命令

/ # ifconfigeth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02          inet addr:10.0.0.2  Bcast:10.0.255.255  Mask:255.255.0.0          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1          RX packets:14 errors:0 dropped:0 overruns:0 frame:0

7 Dockerfile

7.1 About Dockerfile

  • Dockerfile is nothing but the source code for building Docker images
    • Docker can build images automatically by reading the instructions from a Dockerfile
    • A Dockerfile is text document that contains all the commands a user could call on the command line to assemble an image
    • Using docker build users can create an automated build that executes several command-line instructions in succession
s 71

7.2 Dockerfile Format

  • Format

    • # Comment
    • INSTRUCTION arguments
  • The instruction is not case - sensitive

    • However,convention is for them to be UPPERCASE to distinguish them from arguments more easily
  • Docker runs instructions in a Dockerfile in order

  • The first instruction must be FROM in order to specify the Base Image from which you are building

s 72

7.3 Environment replacement

  • Environment variables(declared whit the ENV statement)can also be used in certain instructions as variables to be interpreted by the Dockerfile
  • Environment variables are notated in the Dockerfile either with $variable_name or $
  • The ${variable_name} syntax also supports a few of the standard bash modifiers
    • ${variable:-word} indicates that if variable is set then the result will be that value. If variable is not set then word will be the result.
    • ${variable:+word} indicates that if variable is set then word will be the result,otherwise the result is the empty string.

7.4 .dockerignore file

  • Before the docker CLI sends the context to the docker daemon, it looks for a file named .dockerignore in the root directory of the context

  • If this file exists, the CLI modifies the context to exclue files and directories that match patterns in it

  • The CLI interprets the .dockerignore file as a newline - separated list of patterns similar to the file globs of Unix shells

7.5 Dockerfile Instructions

7.5.1 FROM
  • FROM

    • FROM 指令是最重要的一个且必须为 Dockerfile 文件开篇的第一个非注释行,用于为目标映像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境

    • 实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build 会在 docker 主机上查找指定的镜像文件,在其不存在时,则会从 Docker Hub Registry 上拉取所需的镜像文件

      • 如果好不到指定的镜像文件,docker build 会返回一个错误信息
    • Syntax

      • FROM [:] 或

      • FROM @

        • :指定作为 base image 的名称
        • :base image 的标签,为可选项,省略时默认为latest;
7.5.2 MAINTAINER
  • MAINTANIER(deprecated)

  • 用于让 Dockerfile 制作者提供本人的详细信息

  • Dockerfile 并不限制 MAINTAINER 指令可在出现的位置,但推荐将其放置于 FROM 指令之后

  • Syntax

    • MAINTAINER <author's detail>
      • <author's detail>可是任何文本信息,但约定俗成地使用作者名称及邮件地址
      • MAINTAINER "magedu mage@magedu.com"
7.5.3 LABEL
  • The LABEL instruction adds metadata to an image
    • Syntax:LABEL = = = ...
    • The LABEL instruction adds metadata to an image.
    • A LABEL is a key-value pair
    • To include spaces within a LABEL value, use quotes and backslashes as you would in command-line parsing.
    • An image can have more than one label.
    • You can specify multiple labels on a single line.
7.5.4 COPY
  • COPY

    • 用于从 Docker 主机复制文件至创建的新映像文件

    • Syntax

      • COPY ...

      • COPY ["",... ""]

        • :要复制的源文件或目录,支持使用通配符
        • :目标路径,即正在创建的image的文件系统路径;建议为使用绝对路径,否则,COPY 指令则以WORKDIR 为其起始路径;
      • 注意:在路径中有空白字符时,通常使用第二种格式

  • 文件复制准则

    • 必须是build上下文中的路径,不能是其父目录中的文件
    • 如果是目录,则其内部文件或子目录会被递归复制,但目录自身不会被复制
    • 如果指定了多个,或在中使用了通配符,则必须是一个目录,且必须以/结尾
    • 如果事先不存在,它将会被自动创建,这包括其父目录路径

范例1:

[root@node2 ~]# mkdir img1[root@node2 ~]# cd img1bash[root@node2 img1]# vim Dockerfile
# Descripe:test imageFROM busybox:latestMAINTAINER "CKH <chegnkaihua@ckh.com>"# LABEL maintainer="CKH <chegnkaihua@ckh.com>"COPY index.html /data/web/html/COPY yum.repos.d /etc/yum.repos.d/
[root@node2 img1]# docker build -t tinyhttpd:v0.1-2 ./
Sending build context to Docker daemon   34.3kBStep 1/4 : FROM busybox:latest ---> c55b0f125dc6Step 2/4 : MAINTAINER "CKH <chegnkaihua@ckh.com>" ---> Using cache ---> 8c784eb51b76Step 3/4 : COPY index.html /data/web/html/ ---> Using cache ---> ccd5736d962bStep 4/4 : COPY yum.repos.d /etc/yum.repos.d/ ---> fd57f7f0c97eSuccessfully built fd57f7f0c97eSuccessfully tagged tinyhttpd:v0.1-2
验证镜像:[root@node2 ~]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-1 cat /data/web/html/index.html<h1>Busybox httpd server.</h1>[root@node2 ~]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-2 ls /etc/yum.repos.dCentOS-Base.repoCentOS-Base.repo.BAKCentOS-CR.repoCentOS-Debuginfo.repoCentOS-Media.repoCentOS-Sources.repoCentOS-Vault.repoCentOS-fasttrack.repoCentOS-local.repoCentOS-x86_64-kernel.repodocker-ce.repoelrepo.repo
7.5.5 ADD
  • ADD 指令类似于 COPY 指令,ADD 支持使用 TAR 文件和 URL 路径

  • Syntax

    • ADD ...
    • ADD ["",... ""]
  • 操作准则

    • 同 COPY 指令
    • 如果 为 URL 且 不以 / 结尾,则 指定的文件将被下载并直接被创建为 ;如果 以 / 结尾,则文件名 URL 指定的文件将被直接下载并保存为 /
    • 如果 是一个本地系统上的压缩格式的 tar 文件,它将被展开为一个目录,其行为类似于 "tar -x"命令;然而,通过 URL 获取到的 tar 文件将不会自动展开;
    • 如果 有多个,或其间接或直接使用了通配符,则 必须是一个以 / 结尾的目录路径;如果 不以 / 结尾,则其被视作一个普通文件, 的内容将被直接写入到

范例1:ADD URL

Dockerfile中添加:

ADD https://nginx.org/download/nginx-1.19.10.tar.gz /usr/local/src/

构建镜像:

[root@node2 img1]# docker build -t tinyhttpd:v0.1-3 ./

测试镜像:

[root@node2 ~]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-3 ls /usr/local/srcnginx-1.19.10.tar.gz

范例2:ADD 本地tar文件

Dockerfile中添加:

ADD nginx-1.19.10.tar.gz /usr/local/src/

构建镜像:

[root@node2 img1]# docker build -t tinyhttpd:v0.1-4 ./

测试镜像:

[root@node2 img1]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-4 ls /usr/local/src/nginx-1.19.10
7.5.6 WORKDIR
  • 用于为 Dockerfile 中所有的 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指定设定工作目录

  • Syntax

    • WORKDIR

      • 在 Dockerfile 文件中,WORKDIR 指令可出现多次,其路径也可以为相对路径,不过,其是相对此前一个WORKDIR 指令指定的路径
      • 另外,WORKDIR 也可调用由 ENV 指定定义的变量
    • 例如

      • WORKDIR /var/log
      • WORKDIR $STATEPATH

范例:

Dockerfile 中添加:

WORKDIR /usr/local/src/ADD nginx-1.19.10.tar.gz ./

构建镜像:

[root@node2 img1]# docker build -t tinyhttpd:v0.1-5 ./

测试镜像:

[root@node2 img1]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-5 ls /usr/local/src/nginx-1.19.10
7.5.7 VOLUME
  • 用于在 image 中创建一个挂载点目录,以挂载 Docker host 上的卷或其他容器上的卷

  • Syntax

    • VOLUME
    • VOLUME ["mountpoint"]
  • 如果挂载点目录路径下此前在文件存在,docker run 命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中

范例:

Dockerfile 中添加:

ADD /data/mysql/

构建镜像:

[root@node2 img1]# docker build -t tinyhttpd:v0.1-6 ./

测试镜像:

[root@node2 img1]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-6 mount/dev/mapper/centos-var on /data/mysql type ext4 (rw,relatime)
7.5.8 EXPOSE
  • 用于为容器打开指定要监听的端口以实现与外部通信

  • Syntax

    • EXPOSE [/] [[/] ...]

      • 用于指定传输层协议,可为 tcp 或 udp 二者之一,默认为 TCP 协议
    • EXPOSE 指令可一次指定多个端口,例如

      • EXPOSE 11211/udp 11211/tcp

范例:

Dockerfile中添加:

EXPOSE 80/tcp

构建镜像:

[root@node2 img1]# docker build -t tinyhttpd:v0.1-7 ./

测试镜像:

启动容器:[root@node2 img1]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-7 /bin/httpd -f -h /data/web/html访问容器web服务:[root@node2 img1]# curl 172.17.0.2<h1>Busybox httpd server.</h1>查看端口是否暴露:[root@node2 img1]# docker port tinyweb1此时端口是没有暴露的重新启动容器,加上 -P 选项:[root@node2 img1]# docker run --name tinyweb1 --rm -P tinyhttpd:v0.1-7 /bin/httpd -f -h /data/web/html此时端口是暴露的[root@node2 img1]# docker port tinyweb180/tcp -> 0.0.0.0:4915380/tcp -> :::49153外部浏览器中访问:192.168.2.12:49153可以正常访问
7.5.9 ENV
  • 用于为镜像定义所需的环境变量,并可被 Dockerfile 文件中位于其后的其他指令(如 ENV、ADD、COPY等)所调用

  • 调用格式为:$variable_name 或 $

  • Syntax

    • ENV
    • ENV = ...
  • 第一种格式中,之后的所有内容均会被视作其的组成部分,因此,一次只能设置一个变量;

  • 第二种格式可以一次设置多个变量,每个变量为一个"="的键值对,如果中包含空格,可以以反斜线()进行转义,也可通过对加引号进行标识;另外,反斜线也可用于续行;

  • 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能

范例:

Dockerfile文件:

# Description: test imageFROM busybox:latestMAINTAINER "ckh <chengkaihua@ckh.com>"ENV DOC_ROOT=/data/web/html/  WEB_SERVER_PACKAGE="nginx-1.19.10"COPY index.html ${DOC_ROOT:-/data/web/html/}COPY yum.repos.d /etc/yum.repos.d/WORKDIR /usr/local/ADD ${WEB_SERVER_PACKAGE}.tar.gz ./src/VOLUME /data/mysql/EXPOSE 80/tcp

构建镜像:

[root@node1 imgs]# docker build -t tinyhttpd:v0.1-8 ./

测试镜像:

启动镜像:

[root@node1 imgs]# docker run --name tinyweb1 --rm -P tinyhttpd:v0.1-8 /bin/httpd -f -h /data/web/html

查看一下运行的容器有哪些环境变量:

[root@node1 imgs]# docker run --name tinyweb1 --rm tinyhttpd:v0.1-8 printenvPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=a6a6afa844a9DOC_ROOT=/data/web/html/WEB_SERVER_PACKAGE=nginx-1.19.10HOME=/root

我们还可以在运行容器时给环境变量设值:

[root@node1 imgs]# docker run --name tinyweb1 --rm -P -e WEB_SERVER_PACKAGE="nginx-1.19.1" tinyhttpd:v0.1-8 printenvPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=2b017e6fa62cWEB_SERVER_PACKAGE=nginx-1.19.1DOC_ROOT=/data/web/html/HOME=/root

但是,此时 /usr/local/src 目录中的 nginx版本还是docker build 时的版本:

[root@node1 imgs]# docker run --name tinyweb1 --rm -P -e WEB_SERVER_PACKAGE="nginx-1.19.1" tinyhttpd:v0.1-8 ls /usr/local/srcnginx-1.19.10

因为,这是这是两个阶段:

s 74
7.5.10 RUN
  • 用于指定 docker build 过程中运行的程序,其可以是任何命令

  • Syntax

    • RUN
    • RUN ["","",""]
  • 第一种格式中,通常是一个shell命令,且以"/bin/sh -c" 来运行它,这意味着此进程在容器中的PID不为1,不能接受Unix信号,因此,当使用docker stop 命令停止容器时,此进程接收不到SIGTERM信号;

  • 第二种语法格式中的参数是一个JSON格式的属组,其中为要运行的命令,后面的为传递给命令的选项或参数;然而,此种格式指定的命令不会以"/bin/sh -c"来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。

    • RUN ["/bin/sh","-c","",""]
  • 注意:json 数组中,要使用双引号

范例:

Dockerfile:

[root@node1 imgs]# cat Dockerfile# Description: test imageFROM busybox:latestMAINTAINER "ckh <chengkaihua@ckh.com>"ENV DOC_ROOT=/data/web/html/  WEB_SERVER_PACKAGE="nginx-1.19.10.tar.gz"COPY index.html ${DOC_ROOT:-/data/web/html/}COPY yum.repos.d /etc/yum.repos.d/WORKDIR /usr/local/# ADD ${WEB_SERVER_PACKAGE} ./src/VOLUME /data/mysql/EXPOSE 80/tcpADD https://nginx.org/download/${WEB_SERVER_PACKAGE} /usr/local/src/RUN cd /usr/local/src && \    tar xf ${WEB_SERVER_PACKAGE}

构建镜像:

[root@node1 imgs]# docker build -t tinyhttpd:v0.1-9 ./

测试容器:

[root@node1 imgs]# docker run --name tinyweb1 --rm -it -P tinyhttpd:v0.1-9/usr/local # ls src/nginx-1.19.10         nginx-1.19.10.tar.gz

范例:基于最新版的 Nginx 做一个镜像

大体步骤:

  • FROM centos
  • RUN yum -y install epel-release && yum makecache && yum install nginx
  • 如果想提供新配置文件,ADD一个配置文件放到 /etc/nginx/conf.d/
7.5.11 CMD
  • 类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同

    • RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时**
    • CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令其可以被docker run 的命令行选项所覆盖
    • 在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效
  • Syntax

    • CMD
    • CMD ["","param1",""] 或
    • CMD ["",""]
  • 前两种语法格式的意义同RUN

  • 第三种则用于为ENTRYPOINT

RUN 和 CMD 区别

s 76

(1)它们运行的时间点不同**

RUN 是 docker build 时运行命令

CMD 是在 docker run 时运行命令

(2)它们的运行行为不同**

RUN 运行的命令可以有多个,运行第一个再运行第二个。。。,逐一运行

CMD 运行的命令只有最后一个有效

范例1:RUN 和 CMD 区别

Dockerfile:

FROM busyboxLABEL maintainer="CKH <chengkaihua@ckh.com>" app="httpd"ENV WEB_DOC_ROOT="/data/web/html/"RUN mkdir -p  $WEB_DOC_ROOT && \        echo "<h1>Busybox httpd server.</h1>" > ${WEB_DOC_ROOT}/index.htmlCMD /bin/httpd -f -h ${WEB_DOC_ROOT}

构建镜像:

[root@node1 img2]# docker build -t tinyhttpd:v0.2-1 ./

查看 CMD命令:

[root@node1 imgs]# docker image inspect tinyhttpd:v0.2-1	"Cmd": [		"/bin/sh",		"-c",		"#(nop) ",		"CMD [\"/bin/sh\" \"-c\" \"/bin/httpd -f -h ${WEB_DOC_ROOT}\"]"	],
[root@node1 img2]# docker psCONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS          PORTS     NAMES7f5ec80db8d8   tinyhttpd:v0.2-1   "/bin/sh -c '/bin/ht…"   16 minutes ago   Up 16 minutes             tinyweb2

运行容器时,加上 -it 的话,程序会卡在那,因为我们这里运行的 CMD 命令是内核运行的,没有交互式接口shell:

[root@node1 imgs]# docker run --name tinyweb2 -it --rm -P tinyhttpd:v0.2-1

如果我们运行下面这条命令:

[root@node1 img2]# docker exec -it tinyweb2 /bin/sh
/ # psPID   USER     TIME  COMMAND    1 root      0:00 /bin/httpd -f -h /data/web/html/   14 root      0:00 /bin/sh   20 root      0:00 ps

会发现这条命令的 PID 是 1,因为它默认就执行了 exec 的替换,所以看上去我们启动的 httpd 进程号依然是 1,是为了确保这个容器能自动接收 Unix 信号,比如执行 docker stop 的时候容器能够停掉。

不过,从镜像中我们验证了,它的确是启动为/bin/shell 的子进程的;也验证了,镜像默认启动以后执行的命令被我们改掉了。

范例2:CMD 和 RUN 的区别

Dockerfile:

FROM busyboxLABEL maintainer="CKH <chengkaihua@ckh.com>" app="httpd"ENV WEB_DOC_ROOT="/data/web/html/"RUN mkdir -p  $WEB_DOC_ROOT && \	echo "<h1>Busybox httpd server.</h1>" > ${WEB_DOC_ROOT}/index.html# CMD /bin/httpd -f -h ${WEB_DOC_ROOT}CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]

构建镜像:

[root@node1 img2]# docker build -t tinyhttpd:v0.2-2 ./

我们来看一下镜像中的命令:

[root@node1 img2]# docker image inspect tinyhttpd:0.2-2 "Cmd": [	"/bin/httpd",	"-f",	"-h ${WEB_DOC_ROOT}" ],        

发现,此时镜像中的命令不是运行为 /bin/shell 的子进程,而是直接显示命令本身。

我们运行容器时:

[root@node1 img2]# clear[root@node1 img2]# docker run --name tinyweb2 --rm -P tinyhttpd:0.2-2httpd: can't change directory to ' ${WEB_DOC_ROOT}': No such file or directory

会出现 can't change directory to ' ${WEB_DOC_ROOT}': No such file or directory 错误,这是为什么呢?

因为我们在 Dockerfile 中定义的命令格式是:CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"],它是不会运行为 /bin/shell 的子进程的,所以环境变量 ${WEB_DOC_ROOT} 是用不了的。

我们可以手动把它运行为 /bin/shell 的子命令:

CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]

此时,查看镜像时,它是运行为 /bin/sh 的子命令的:

[root@node1 img2]# docker build -t tinyhttpd:v0.2-3 ./[root@node1 img2]# docker image inspect tinyhttpd:v0.2-3  "Cmd": [	"/bin/sh",	"-c",	"#(nop) ",	"CMD [\"/bin/sh\" \"-c\" \"/bin/httpd\" \"-f\" \"-h ${WEB_DOC_ROOT}\"]"  ],
7.5.12 ENTRYPOINT
  • 类似 CMD 指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序

  • 与 CMD 不同的是,由 ENTRYPOINT 启动的程序不会被 docker run 命令行指定的参数所覆盖,而且,这些命令行参数会被当做参数传递给 ENTRYPOINT 指令指定的程序

    • 不过,docker run 命令的 --entrypoint 选项的参数可覆盖 ENTRYPOINT 指令指定的程序
  • Syntax

    • ENTRYPOINT
    • ENTRYPOINT ["","",""]
  • docker run 命令传入的命令参数会覆盖 CMD 指令的内容并且附加到 ENTRYPOINT 命令最后做为其参数使用

  • Dockerfile 文件中也可以存在多个 ENTRYPOINT 指令,但仅有最后一个会生效

范例1:

Dockerfile:

FROM busyboxLABEL maintainer="CKH <chengkaihua@ckh.com>" app="httpd"ENV WEB_DOC_ROOT="/data/web/html/"RUN mkdir -p  $WEB_DOC_ROOT && \	echo "<h1>Busybox httpd server.</h1>" > ${WEB_DOC_ROOT}/index.html# CMD /bin/httpd -f -h ${WEB_DOC_ROOT}# CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]ENTRYPOINT /bin/httpd -f -h ${WEB_DOC_ROOT}

构建镜像:

[root@node1 img2]# docker build -t tinyhttpd:v0.2-4 ./

此时运行容器时,ls 运行的命令是不会显示的,它只会当做参数传递给 ENTRYPOINT 并补在其命令后面:

[root@node1 img2]# docker run --name tinyweb2 --rm -P -it tinyhttpd:v0.2-4 ls /data/web/html/

要想在 docker run 时的命令覆盖掉 ENTRYPOINT 默认的命令,我们可以使用 --entrypoint 选项:

 [root@node1 img2]# docker run --name tinyweb2 --rm -P -it --entrypoint ls /data/web/html tinyhttpd:v0.2-4

不过,多数情况下,我们不会去覆盖。

我们知道,前面 CMD 命令如果有多条的时候,只有最后一个 CMD 有效,同样的, ENTRYPOINT 如果有多个的时候,也是最后一个有效

如果CMD 和 ENTRYPOINT 同时定义的话,CMD 的命令会被当做参数传递给 ENTRYPOINT,并补在其命令后面

所以,CMD 和 ENTRYPOINT 同时用时,CMD 可以为 ENTRYPOINT 命令传递参数

范例:

Dockerfile:

[root@node1 img2]# clear[root@node1 img2]# docker build -t tinyhttpd:v0.2-4 ./FROM busyboxLABEL maintainer="CKH <chengkaihua@ckh.com>" app="httpd"ENV WEB_DOC_ROOT="/data/web/html/"RUN mkdir -p  $WEB_DOC_ROOT && \        echo "<h1>Busybox httpd server.</h1>" > ${WEB_DOC_ROOT}/index.html# CMD /bin/httpd -f -h ${WEB_DOC_ROOT}CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]ENTRYPOINT /bin/sh -c

构建成镜像后查看镜像:

[root@node1 img2]# docker build -t tinyhttpd:v0.2-6 ./[root@node1 img2]# docker image inspect tinyhttpd:v0.2-6
   "Cmd": [                "/bin/httpd",                "-f",                "-h ${WEB_DOC_ROOT}"	],	"Entrypoint": [                "/bin/sh",                "-c",                "/bin/sh -c"	],

会发现 /bin/sh 执行两遍,这是因为定义 ENTRYPOINT 时,此种格式会默认以 /bin/sh 的子命令去执行定义的命令:

ENTRYPOINT /bin/sh -c

修改 Dockerfile :

FROM busyboxLABEL maintainer="CKH <chengkaihua@ckh.com>" app="httpd"ENV WEB_DOC_ROOT="/data/web/html/"RUN mkdir -p  $WEB_DOC_ROOT && \        echo "<h1>Busybox httpd server.</h1>" > ${WEB_DOC_ROOT}/index.html# CMD /bin/httpd -f -h ${WEB_DOC_ROOT}CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]ENTRYPOINT ["/bin/sh","-c"]

查看构建的镜像:

"Cmd": [
	"/bin/httpd",
	"-f",
	"-h ${WEB_DOC_ROOT}"
],
"Entrypoint": [
	"/bin/sh",
	"-c"
],

我们运行容器:

[root@node1 img2]# docker run --name tinyweb2 --rm -it -P tinyhttpd:v0.2-8 "ls /data"
web

此时,ls 命令会作为参数传递给 ENTRYPOINT,而之前 CMD 传递给 ENTRYPOINT 的参数会被 ls 这条命令覆盖掉,所以也就相当于执行的是:

/bin/sh -c ls /data
7.5.13 完整示例:将 Nginx 做成镜像
[root@node1 img3]# ls
Dockerfile  entrypoint.sh  index.html

Dockerfile:

FROM nginx:1.14-alpine
LABEL maintainer="ckh <chengkaihua@ckh.com>"

ENV NGX_DOC_ROOT="/data/web/html/"

ADD index.html ${NGX_DOC_ROOT}

ADD entrypoint.sh /bin/

EXPOSE 80/tcp

CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]

entrypoint.sh 提供 Nginx 的配置文件:

#! /bin/sh
#
cat > /etc/nginx/conf.d/www.conf << EOF
server {
	server_name ${HOSTNAME};
	listen ${LISTENING_IP:-0.0.0.0}:${PORT:-80};
	root ${NGX_DOC_ROOT:-/usr/share/nginx/html};
}
EOF

exec "$@"

构建镜像:

[root@node1 img3]# docker build -t nginx:v0.3-1 ./

运行容器:

[root@node1 img3]# docker run --name myweb11 --rm -it -P nginx:v0.3-1

测试镜像:

[root@node1 img3]# docker exec -it myweb11 /bin/sh
/ # wget -O - -q 40d2b6fa28c3
<h1>New Doc Root for Nginx</h1>

当然,我们的主要目的是借助于 环境变量,在docker run 时生成配置文件,我们可以通过 -e 选项来提供环境变量:

[root@node1 img3]# docker run --name myweb11 --rm -it -P -e "PORT=8080" nginx:v0.3-1
[root@node1 img3]# docker exec -it myweb11 /bin/sh
/ # netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
7.5.14 USER
  • 用于指定运行 image 时的或运行 Dockerfile 中任何 RUN、CMD 或 ENTRYPOINT 指令指定的程序时的用户名或 UID

  • 默认情况下,container 的运行身份为 root 用户

  • Synatax

    • USER |
    • 需要注意的是, 可以为任意数字,但实践中其必须为/etc/passwd中某用户的有效UID,否则,docker run 命令将运行失败
7.5.15 HEALTHCHECK
  • The HEALTHCHECK instruction tells Docker how to test a container to check that it is still working。
  • This can detect cases such as a web server that is stuck in an infinite loop and unable to handle new connections,even though the server process is still running。
  • The HEALTHCHECK instruction has two forms;
    • HEALTHCHECK [OPTIONS] CMD command (check container health by running a command inside the container)
    • HEALTHCHECK NONE (disable any healthcheck inherited from the base image)
7.5.16 HEALTHCHECK(2)
  • The options that can appear before CMD are:

    • --interval=DURATION(DEFAULT:30s)
    • --timeout=DURATION(default:30s)
    • --start-period=DURATION(default:0s)
    • --retries=N(default:3)
  • The command's exit status indicates the health status of the container.The possible values are:

    • 0:success - the container is healthy and ready for use
    • 1:unhealthy - the container is not working correctly
    • 2:reserved - do not use this exit code
  • For example

范例:

以 上面的 Nginx 镜像示例,Dockerfile 中添加如下代码:

FROM nginx:1.14-alpine
LABEL maintainer="ckh <chengkaihua@ckh.com>"

ENV NGX_DOC_ROOT="/data/web/html/"

ADD index.html ${NGX_DOC_ROOT}

ADD entrypoint.sh /bin/

EXPOSE 80/tcp

HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/

CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]

构建镜像:

[root@node1 img3]# docker build -t nginx:v0.3-2 ./

运行容器:

[root@node1 img3]# docker run --name myweb11 --rm -it -P -e "PORT=8080" nginx:v0.3-2
127.0.0.1 - - [19/May/2021:07:57:49 +0000] "GET / HTTP/1.1" 200 32 "-" "Wget" "-"
127.0.0.1 - - [19/May/2021:07:58:19 +0000] "GET / HTTP/1.1" 200 32 "-" "Wget" "-"

从上面的健康状态检测结果中,我们发现是 Nginx 服务是健康的。

为了测试效果,我们将 Dockerfile 中端口改成一个不存在的端口,并且写成固定的:

HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:10080/

再次构建镜像并运行容器:

[root@node1 img3]# docker build -t nginx:v0.3-4 ./
[root@node1 img3]# docker run --name myweb11 --rm -P nginx:v0.3-4

会发现,健康状态检测失败后会自动退出容器

7.5.17 SHELL
  • The SHELL instruction allows the default shell used for the shell form of commands to be overridden.

  • The default shell on Linux is ["/bin/sh","-c"],and on Windows is ["cmd","/S","/C"].

  • The SHELL instruction must be written in JSON form in a Dockerfile.

    • Syntax:SHELL ["executable","parameters"]
  • The SHELL instruction can appear multiple times.

  • Each SHELL instruction overrides all previous SHELL instructions,and affects all subsequent instructions.

7.5.18 STOPSIGNAL
  • STOPSIGNAL
    • The STOPSIGNAL instruction sets the system call signal that will be sent to the container to exit.
    • This signal can be a valid unsigned number that matches a position in the kernel's syscall table,for instance 9,or a signal name in the format SIGNAME,for instance SIGKILL.
    • Syntax:STOPSIGNAL signal

7.5.19 ARG

  • The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command using the --build-arg = flag.
  • if a user specifies a build argument that was not defined in the Dockerfile.the build outputs a warning.
  • Syntax:ARG [=]
  • A Dockerfile may include one or more ARG instructions.
  • An ARG instruction can optionally include a default value:
    • ARG version=1.14
    • ARG user=magedu

范例:

FROM nginx:1.14-alpine

ARG author="ckh <chengkaihua@ckh.com>"
LABEL maintainer="${author}"

ENV NGX_DOC_ROOT="/data/web/html/"
ADD index.html ${NGX_DOC_ROOT}
ADD entrypoint.sh /bin/
EXPOSE 80/tcp
HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:10080/
CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]

构建镜像:

[root@node1 img3]# docker build --build-arg author="pony <pony@qq.com>" -t nginx:v0.3-7 ./

查看镜像:

[root@node1 img3]# docker image inspect nginx:v0.3-7
"Labels": {
	"maintainer": "pony <pony@qq.com>"
},
7.5.19 ONBUILD
  • 用于在 Dockerfile 中定义一个触发器

  • Dockerfile 用于 build 映像文件,此映像文件亦可作为 base image 被另一个 Dockerfile 用作 FROM 指令的参数,并以之构建新的映像文件

  • 在后面的这个 Dockerfile 中的 FROM 指令在 build 过程中被执行时,将会"触发"创建其 base image 的 Dockerfile 文件中的 ONBUILD 指令定义的触发器

  • Syntax

    • ONBUILD
  • 尽管任何指令都可注册成为触发器指令,但 ONBUILD 不能自我嵌套,且不会触发 FROM 和 MAINTAINER 指令

  • 使用包含 ONBUILD 指令的 Dockerfile 构建的镜像应该使用特殊的标签,例如ruby:2.0-onbuild

  • 在 ONBUILD 指令中使用 ADD 或 COPY 指令应该格外小心,因为新构建过程的上下文在缺少指定的源文件时会失败

范例:

Dockerfile 中加了 ONBUILD:

FROM nginx:1.14-alpine
ARG author="ckh <chengkaihua@ckh.com>"
LABEL maintainer="${author}"
ENV NGX_DOC_ROOT="/data/web/html/"
ADD index.html ${NGX_DOC_ROOT}
ADD entrypoint.sh /bin/
EXPOSE 80/tcp
HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:10080/

ONBUILD ADD https://nginx.org/download/nginx-1.20.0.tar.gz /usr/local/src/

CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]
~

构建成镜像:

[root@node1 ~]# docker build -t nginx:v0.3-8 ./

我们再新创建一个 Dockerfile 用来测试 ONBUILD:

FROM nginx:v0.3-8

RUN mkdir /tmp/test

构建成镜像:

[root@node1 ~]# docker build -t nginx:v0.4-1 ./
Sending build context to Docker daemon  115.7MB
Step 1/2 : FROM nginx:v0.3-8
# Executing 1 build trigger
Downloading [==================================================>]  1.061MB/1.061MB
 ---> 1130dd9ceb40
Step 2/2 : RUN mkdir /tmp/test
 ---> Running in 0998f0abd30e
Removing intermediate container 0998f0abd30e
 ---> 0ef86c64d355
Successfully built 0ef86c64d355
Successfully tagged nginx:v0.4-1

运行容器时也会发现文件已被下载到指定目录:

[root@node1 ~]# docker run --name test1 --rm nginx:v0.4-1 ls /usr/local/src/
nginx-1.20.0.tar.gz

8 Docker Registry

8.1 Registry(repository and index)

  • Repository

    • 由某特定的 docker 镜像的所有迭代版本组成的镜像仓库

    • 一个 Registry 中可以存在多个 Repository

      • Repository 可分为"顶层仓库"和"用户仓库"
      • 用户仓库名称格式为"用户名/仓库名"
    • 每个参股可以包含多个Tag(标签),每个标签对应一个镜像

  • Index

    • 维护用户账户、镜像的校验以及公共命名空间的信息
    • 相当于为 Registry 提供了一个完成用户认证等功能的检索接口

8.2 Docker Registry 分类

  • Registry 用于保存 docker 镜像,包括镜像的层次结构和元数据
  • 用户可自建 Registry,也可使用官方的 Docker Hub
  • 分类
    • Sponsor Registry:第三方的 registry,供客户和 Docker 社区使用
    • Mirror Registry:第三方的 registry,只让客户使用
    • Vendor Registry:由发布 Docker 镜像的供应商提供的 registry
    • Private Registry:通过设有防火墙和额外的安全层的私有实体提供的 registry

8.3 Private Registry

为了能够帮我们快速创建私有registry,docker专门提供了一个程序包叫:docker-distribution

我们可以在 docker hub 中搜索 registry 找到这个程序包。

或者我们也可以直接使用 epel 源中的程序包,直接安装即可。

范例:

在node2:192.168.2.12 上安装 epel 源中的 docker-registry:

[root@node1 ~]# yum install -y docker-registry
[root@node1 ~]# rpm -ql docker-distribution
/etc/docker-distribution/registry/config.yml
/usr/bin/registry
/usr/lib/systemd/system/docker-distribution.service
/usr/share/doc/docker-distribution-2.6.2
/usr/share/doc/docker-distribution-2.6.2/AUTHORS
/usr/share/doc/docker-distribution-2.6.2/CONTRIBUTING.md
/usr/share/doc/docker-distribution-2.6.2/LICENSE
/usr/share/doc/docker-distribution-2.6.2/MAINTAINERS
/usr/share/doc/docker-distribution-2.6.2/README.md
/var/lib/registry

配置文件:/etc/docker-distribution/registry/config.yml

cat /etc/docker-distribution/registry/config.yml
version: 0.1
log:
  fields:
    service: registry
storage:
    cache:
        layerinfo: inmemory
    filesystem:
        rootdirectory: /var/lib/registry
http:
    addr: :5000

我们直接启动服务:

[root@node1 registry]# systemctl start docker-distribution

下面我们来推送一个镜像:

(1) 给镜像打标,指明另一个节点的名字和监听的端口,并且指明仓库:

[root@node1 registry]# docker tag nginx:v0.3-8 node2.ckh.com:5000/nginx:0.3-8

(2) 推送镜像

[root@node1 registry]# docker push node2.ckh.com:5000/nginx:v0.3-8
The push refers to repository [node2.ckh.com:5000/nginx]
Get https://node2.ckh.com:5000/v2/: http: server gave HTTP response to HTTPS client

会发现报错了,这是因为 node2 私有仓库响应时是 https 协议,而这里 node1 是 http 协议。

在 node1 中 /etc/docker/daemon.json 中添加如下行:指明这是不安全的registry,所以联系时可以是http协议。

"insecure-registries": ["node2.ckh.com:5000"],

重启docker服务后,再push镜像:

[root@node1 registry]# docker push node2.ckh.com:5000/nginx:v0.3-8

在 node2 上,我们可以看到镜像push到node2的仓库了:

[root@node2 ~]# cd /var/lib/registry/
[root@node2 registry]# ls
docker

其他节点要想下载镜像,使用如下命令:

[root@node2 v2]# docker pull node2.ckh.com:5000/nginx:v0.3-8
8.3.1 docker 参考手册

Docker 参考手册:

https://docs.docker.com/engine/reference/commandline/dockerd/

配置 docker 守护进程的属性信息的方法:``/etc/docker/daemon.json`

  • 每一个可设置的键是 dockerd 的可用的选项,其值为选项的参数;但有些参数不可用于此文件中,例如 add-registry,``insecure-registry`;

    • 有些选项的参数是属组的格式,需要放置于 [];
  • 官方手册(完整的可用参数列表):

    • https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file
{
  "allow-nondistributable-artifacts": [],
  "api-cors-header": "",
  "authorization-plugins": [],
  "bip": "",
  "bridge": "",
  "cgroup-parent": "",
  "cluster-advertise": "",
  "cluster-store": "",
  "cluster-store-opts": {},
  "containerd": "/run/containerd/containerd.sock",
  "containerd-namespace": "docker",
  "containerd-plugin-namespace": "docker-plugins",
  "data-root": "",
  "debug": true,
  "default-address-pools": [
    {
      "base": "172.80.0.0/16",
      "size": 24
    },
    {
      "base": "172.90.0.0/16",
      "size": 24
    }
  ],
  "default-cgroupns-mode": "private",
  "default-gateway": "",
  "default-gateway-v6": "",
  "default-runtime": "runc",
  "default-shm-size": "64M",
  "default-ulimits": {
    "nofile": {
      "Hard": 64000,
      "Name": "nofile",
      "Soft": 64000
    }
  },
  "dns": [],
  "dns-opts": [],
  "dns-search": [],
  "exec-opts": [],
  "exec-root": "",
  "experimental": false,
  "features": {},
  "fixed-cidr": "",
  "fixed-cidr-v6": "",
  "group": "",
  "hosts": [],
  "icc": false,
  "init": false,
  "init-path": "/usr/libexec/docker-init",
  "insecure-registries": [],
  "ip": "0.0.0.0",
  "ip-forward": false,
  "ip-masq": false,
  "iptables": false,
  "ip6tables": false,
  "ipv6": false,
  "labels": [],
  "live-restore": true,
  "log-driver": "json-file",
  "log-level": "",
  "log-opts": {
    "cache-disabled": "false",
    "cache-max-file": "5",
    "cache-max-size": "20m",
    "cache-compress": "true",
    "env": "os,customer",
    "labels": "somelabel",
    "max-file": "5",
    "max-size": "10m"
  },
  "max-concurrent-downloads": 3,
  "max-concurrent-uploads": 5,
  "max-download-attempts": 5,
  "mtu": 0,
  "no-new-privileges": false,
  "node-generic-resources": [
    "NVIDIA-GPU=UUID1",
    "NVIDIA-GPU=UUID2"
  ],
  "oom-score-adjust": -500,
  "pidfile": "",
  "raw-logs": false,
  "registry-mirrors": [],
  "runtimes": {
    "cc-runtime": {
      "path": "/usr/bin/cc-runtime"
    },
    "custom": {
      "path": "/usr/local/bin/my-runc-replacement",
      "runtimeArgs": [
        "--debug"
      ]
    }
  },
  "seccomp-profile": "",
  "selinux-enabled": false,
  "shutdown-timeout": 15,
  "storage-driver": "",
  "storage-opts": [],
  "swarm-default-advertise-addr": "",
  "tls": true,
  "tlscacert": "",
  "tlscert": "",
  "tlskey": "",
  "tlsverify": true,
  "userland-proxy": false,
  "userland-proxy-path": "/usr/libexec/docker-proxy",
  "userns-remap": ""
}
8.3.2 Harbor

CNCF: Cloud Native Computing Foundation,云原生计算基金会,由Google、IBM、微软等几家巨头牵头成立的一个专门用来维护 K8s项目的第三方组织。目前这个组织已经有好几个项目了。其中就有刚加入的一个私有仓库服务器软件叫 Harbor。

这是由 vmware 在docker registry 基础之上做了二次开发,加进去了很多额外程序,包含非常漂亮的 web界面。因此,我们可以拿它来构建本地完整的私有仓库。甚至于我们在互联网上买了证书以后,可以把它构建成公共的仓库。

  • Project Harbor is an open source trusted cloud native registry project that stores,signs,and scans content

    • Harbor extends the open source Docker Distribution by adding the functionalities usually required by users such as security,identity and management.
    • Harbor supports advanced features such as user management,access control,activity monitoring,and replication between instances.
  • Featuers

    • Multi-tenant content signing and validation
    • Security and vulnerability analysis
    • Audit logging
    • Identity integration and role-based access control
    • Image replication between instances
    • Extensible API and graphical UI
    • Internationalization (currently English and Chinese)

参考文档:https://goharbor.io/docs/2.0.0/install-config/#installation-process

下载地址:https://github.com/goharbor/harbor/releases

8.3.3 Docker Compose

它是一个单机编排工具。我们要使用 Docker Compose,就要写编排脚本。

参考文档:https://docs.docker.com/compose/

范例:

version: "3.9"
services:
  webapp:
    build:
      context: ./dir
      dockerfile: Dockerfile-alternate
      args:
        buildno: 1
8.3.4 范例:Harbor结合Compose 建立私有Registry

下载 harbor:https://storage.googleapis.com/harbor-releases/release-1.4.0/harbor-offline-installer-v1.4.0.tgz

安装并配置 harbor:

[root@node1 harbor]# tar xf harbor-offline-installer-v1.4.0.tgz -C /usr/local/
[root@node1 harbor]# cd /usr/local
[root@node1 harbor]# cd harbor/
[root@node1 harbor]# vim harbor.cfg
修改主机名等配置

安装 Compose:

[root@node1 harbor]# yum -y install docker-compose

执行 install.sh 启动 harbor,它会自动装入镜像,可能过程有点慢:

[root@node2 harbor]# ./install.sh[Step 0]: checking installation environment ...Note: docker version: 20.10.6Note: docker-compose version: 1.18.0[Step 1]: loading Harbor images ...

s 78

默认登录用户名和密码:

adminharbor12345

s 77

s 79

s 80

s 81

s 82

harbor 还支持复制功能。

普通用户登录时,界面是这样的。我们可以新建项目。

s 83

新建镜像怎么推送呢:

因为是非安全的仓库,首先要更改下 daemon.json

s 84

对镜像重新打标:

[root@node2 ~]# docker tag myweb:v0.3-1 node02.magedu.com/devel/myweb:v0.3-1

push 镜像:

[root@node2 ~]# docker login node02.magedu.com
[root@node2 ~]# docker push node02.magedu.com/devel/myweb:v0.3-1

harbor 管理命令:

[root@node2 ~]# docker-compose --help : 查看帮助[root@node2 ~]# docker-compose pause :暂停 harbor 服务[root@node2 ~]# docker-compose stop :停止[root@node2 ~]# docker-compose start :启动[root@node2 ~]# docker-compose logs :查看日志...

9 Docker 的系统资源限制

9.1 Limit a container's resources

  • By default,a container has no resource constraints and can use as much of a given resource as the host's kernel scheduler allows.
  • Docker provides ways to control how much memory,CPU,or block IO a container can use, setting runtime configuration flags of the docker run command.
  • Many of these features require your kernel to support Linux capabilities.
    • To check for support,you can use the docker info command.

9.2 Resource allowances

  • Eight-sided containers

s 85

9.2.1 Memory
  • OOME
    • On Linux hosts,if the kernel detects that there is not enough memory to perform important system functions,it throws an OOME,or Out Of Memory Exception,and starts killing processes to free up memory.
      • 一旦发生 OOME,任何进程都有可能被杀死,包括 docker daemon 在内
      • 为此,Docker 特地调整了 docker daemon 的 OOM 优先级,以免它被内核"正法",但容器的优先级并为被调整
9.2.1.1 Limit a container's access to memory

s 86

9.2.2 --memory-swap
  • Using swap allows the container to write excess memory requirements to disk when the container has exhausted all the RAM that is available to it.
  • --memory-swap is a modifier flag that only has meaning if --memory is also set.

s 87

9.2.3 CPU
  • By default,each container‘s access to the host machine's CPU cycles is unlimited.
  • You can set various constraints to limit a given container's access to the host machine's CPU cycles.
  • Most users use and configure the default CFS scheduler.
  • In Docker 1.13 and higher,you can also configure the realtime scheduler.
9.2.3.1 Configure the default CFS scheduler

s 88

9.2.4 压力测试范例

范例:限制容器总内存大小为 256M,启动两个进程来进行压测:发现内存总占用不超过256M

[root@node2 harbor]# docker run --name stress -it --rm -m 256m lorel/docker-stress-ng:0.03.16 stress --vm 2stress-ng: info: [1] defaulting to a 86400 second run per stressorstress-ng: info: [1] dispatching hogs:  2 vm
[root@node2 ~]# docker statsCONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O       BLOCK I/O     PIDS79d6e9831719   stress    1.25%     255.8MiB / 256MiB   99.93%    1.02kB / 0B   4.07GB / 0B   5CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O       BLOCK I/O     PIDS79d6e9831719   stress    1.25%     255.8MiB / 256MiB   99.93%    1.02kB / 0B   4.07GB / 0B   5

范例:对 cpu 进行测试,测试运允许 2个核运行,启动 8个进程进行压测:发现CPU占用率基本上是百分之两百

[root@node2 harbor]# docker run --name stress -it --rm --cpus 2  lorel/docker-stress-ng:0.03.16 stress --cpu 8stress-ng: info: [1] defaulting to a 86400 second run per stressorstress-ng: info: [1] dispatching hogs:  8 cpu
[root@node2 ~]# docker statsCONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O     PIDS3546f2da6cee   stress    200.70%   12.93MiB / 978.2MiB   1.32%     946B / 0B   5.87MB / 0B   9CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O     PIDS3546f2da6cee   stress    200.70%   12.93MiB / 978.2MiB   1.32%     946B / 0B   5.87MB / 0B   9

范例:限制进程只在哪个cpu核心上运行:

[root@node2 harbor]# docker run --name stress -it --rm --cpuset-cpus 0,2  lorel/docker-stress-ng:0.03.16 stress --cpu 8stress-ng: info: [1] defaulting to a 86400 second run per stressorstress-ng: info: [1] dispatching hogs:  8 cpu
[root@node2 ~]# docker statsCONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O   PIDS180aea18ea65   stress    200.61%   12.84MiB / 978.2MiB   1.31%     946B / 0B   0B / 0B     9CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O   PIDS180aea18ea65   stress    200.61%   12.84MiB / 978.2MiB   1.31%     946B / 0B   0B / 0B     9

范例:--cpu-shares,如果只启动一个容器,cpu是不会被限制的

[root@node2 harbor]# docker run --name stress -it --rm --cpu-shares 1024  lorel/docker-stress-ng:0.03.16 stress --cpu 8stress-ng: info: [1] defaulting to a 86400 second run per stressorstress-ng: info: [1] dispatching hogs:  8 cpu
[root@node2 ~]# docker statsCONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT    MEM %     NET I/O     BLOCK I/O     PIDS719eeac3118f   stress    406.40%   14.7MiB / 978.2MiB   1.50%     876B / 0B   3.75MB / 0B   9CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT    MEM %     NET I/O     BLOCK I/O     PIDS719eeac3118f   stress    406.40%   14.7MiB / 978.2MiB   1.50%     876B / 0B   3.75MB / 0B   9

如果我们启动的容器是 2:1 的比例来分配的,那么统计数据中可以看到 cpu 使用率也是 2:1 的关系:

[root@node2 harbor]# docker run --name stress1 -it --rm --cpu-shares 1024  lorel/docker-stress-ng:0.03.16 stress --cpu 8stress-ng: info: [1] defaulting to a 86400 second run per stressorstress-ng: info: [1] dispatching hogs:  8 cpu^Cstress-ng: info: [1] successful run completed in 15.54s
[root@node2 ~]# docker run --name stress2 -it --rm --cpu-shares 512  lorel/docker-stress-ng:0.03.16 stress --cpu 8stress-ng: info: [1] defaulting to a 86400 second run per stressorstress-ng: info: [1] dispatching hogs:  8 cpu^Cstress-ng: info: [1] successful run completed in 36.62s
[root@node2 ~]# docker statsCONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O     PIDS9431a50ffcd3   stress1   271.61%   12.89MiB / 978.2MiB   1.32%     586B / 0B   164kB / 0B    949cbf5cb5862   stress    135.26%   15.22MiB / 978.2MiB   1.56%     946B / 0B   5.78MB / 0B   9
posted @ 2022-01-10 18:21  coocoo  阅读(113)  评论(0编辑  收藏  举报