docker & docker conpose

Docker

使用Docker容器化封装应用程序的意义(好处)

  • Docker引擎统一了基础设施环境 - docker环境
    • 硬件操作
    • 操作系统的版本
    • 运行时环境异构
  • Docker引擎统一了程序打包(装箱)方式 - docker镜像
    • java程序
    • python程序
    • go程序
    • ...
  • DOcker引擎统一了程序部署(运行)方式 - docker容器
    • java - jar -> docker run
    • python manage.py runserver -> docker run
    • go ./main.go -> docker run

使用Docker容器化封装应用程序的意义(缺点)

  • 单机使用,无法有效集群
  • 随着容器数量的上升,管理成本攀升
  • 没有有效的容灾/自愈机制
  • 没有预设编排模板,无法实现快速、大规模容器调度
  • 没有统一的配置管理中心工具
  • 没有容器生命周期的管理工具
  • 没有图形化运维管理工具

下载安装

Linux

  1. 安装依赖包

    $ sudo yum install -y yum-utils device-mapper-persistent-data lvm2
    
  2. 设置阿里云镜像源 #

    $ sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 
    
  3. 安装 Docker-CE

    重建 Yum 缓存。

    $ yum makecache fast
    

    安装 Docker-CE ,请执行一下命令进行安装:

    $ sudo yum install docker-ce
    

    Linux Docker配置文件地址/etc/docker/daemon.json

  4. 启动 Docker-CE

    $ sudo systemctl enable docker
    $ sudo systemctl start docker
    
  5. [可选] 为 Docker 建立用户组#

    docker 命令与 Docker 引擎通讯之间通过 UnixSocket ,但是能够有权限访问 UnixSocket 的用户只有 root 和 docker 用户组的用户才能够进行访问,所以我们需要建立一个 docker 用户组,并且将需要访问 docker 的用户添加到这一个用户组当中来。

    1. 建立 Docker 用户组

      $ sudo groupadd docker
      
    2. 添加当前用户到 docker 组

      $ sudo usermod -aG docker $USER
      $ sudo systemctl enable docker
      $ sudo systemctl start docker
      
  6. 镜像加速配置#

    这里使用的是 阿里云提供的镜像加速 ,登录并且设置密码之后在左侧的 Docker Hub 镜像站点 可以找到专属加速器地址,复制下来。

    阿里云镜像加速官网

    然后执行以下命令:

    $ sudo mkdir -p /etc/docker
    $ sudo tee /etc/docker/daemon.json <<-'EOF'
    {
      "registry-mirrors": ["你的加速器地址"],
      "dns":["192.168.56.2","223.5.5.5"], # 选填 增加dns解析
      "bip": xxx.xx.x.xx, # 选填 更改docker 自己的网络桥地址
      "hosts": ["tcp://ip:端口","unix:///var/run/docker/sock"], # 选填 跟修改vi /usr/lib/systemd/system/docker.service  中的 ExecStart 一致
      "data-root":"/data/docker"	# 选填 指定存放docker下载文件以及其他存储地址 默认在/var/lib/docker/
      "cluster-store":"consul://启动consul的设备ip:端口", # 选填 多台设备集群参数
      "cluster-advertise":"本机ip:2375" # 必须配置下面远程控制的参数 vi /usr/lib/systemd/system/docker.service 
    }
    EOF
    $ sudo systemctl daemon-reload
    $ sudo systemctl restart docker
    

    如果需要远程控制

    $ vi /usr/lib/systemd/system/docker.service 
    

    修改

    ExecStart=/usr/bin/dockerd -H tcp://ip  -H unix:///var/run/docker.sock # -H unix:///var/run/docker.sock 是本地访问 必须要加
    

    之后重新加载配置,并且重启 Docker 服务

    $ systemctl daemon-reload
    $ systemctl restart docker
    

MAC

详细安装

$ brew cask install docker

手动下载

https://download.docker.com/mac/stable/Docker.dmg
https://download.docker.com/mac/edge/Docker.dmg

镜像加速配置

镜像加速配置 访问阿里查看详细demo

Mac桌面版

​ 右键点击桌面顶栏的 docker 图标,选择 Preferences ,在 Daemon 标签(Docker 17.03 之前版本为 Advanced 标签)下的 Registry mirrors 列表中将 https://mk3q07hr.mirror.aliyuncs.com 加到"registry-mirrors"的数组里,点击 Apply & Restart按钮,等待Docker重启并应用配置的镜像加速器。

命令

帮助命令

$ docker version # 查看docker版本

$ docker info # 查看docker更加详细的信息
# Containers 容器数量  
# Running 运行数量  
# Paused 暂停状态 
# Stopped 停止状态 
# Images 镜像数量  
# Server Version 服务器版本 
# Storage Driver 存储驱动后端 
# Plugins  插件  
# Volume 存储插件 
# Network网络插件
# Log 日志插件 
# Security Options 安全选项  
# Kernel Version 内核版本  
# Registry Mirrors 加速镜像

$ docker 命令 --help # 获取命令帮助

镜像命令

查看所有镜像

docker images

$ docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
# 解释
REPOSITORY 镜像的仓库源
TAG	镜像的标签
IMAGE ID 镜像的ID
CREATED 镜像的创建时间
SIZE 镜像的大小

# 常用可选项
  -a, --all             # 列出所有镜像
  -q, --quiet           # 只显示镜像的ID
  
$ docker history 镜像ID/镜像名称 # 查看镜像层级
搜索镜像

docker search

$ docker search 镜像
$ docker search mysql
NAME                              DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
mysql                             MySQL is a widely used, open-source relation…   10202               [OK]                
mariadb                           MariaDB is a community-developed fork of MyS…   3753                [OK]                
mysql/mysql-server                Optimized MySQL Server Docker images. Create…   744                                     [OK]

# 常用可选项
  -f, --filter filter   # 通过条件过滤 例如 -f=STARS=3000 超过3000收藏的显示出来
下载镜像

docker pull

$ docker pull 镜像[:tag]

$ docker pull mysql # 下载最新版本的

$ docker pull mysql:5.7 # 下载指定版本
852e50cd189d: Pull complete  # 分层下载:docker image的核心 联合文件系统 如果其他镜像也有一致的层级就不用重复下载
29969ddb0ffb: Pull complete 
a43f41a44c48: Pull complete 
5cdd802543a3: Pull complete 
b79b040de953: Pull complete 
938c64119969: Pull complete 
7689ec51a0d9: Pull complete 
36bd6224d58f: Pull complete 
cab9d3fa4c8c: Pull complete 
1b741e1c47de: Pull complete 
aac9d11987ac: Pull complete 
Digest: sha256:8e2004f9fe43df06c3030090f593021a5f283d028b5ed5765cc24236c2c4d88e # 数字签名
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7 # 真实的地址 使用 docker pull docker.io/library/mysql:5.7 和 docker pull mysql:5.7 是一样的指令

删除镜像

docker rmi

$ docker rmi -f 镜像ID/镜像名称 # -f 表示强制删除

$ docker rmi -f xxxx
$ docker rmi -f xxxx xxxxx2 # 删除多个容器

$ docker rmi -f $(docker images -aq) # 删除所有镜像

容器命令

启动容器

docker run

$ docker run [可选参数] 镜像

# 参数说明
--name="Name" # 容器名称,用来区分容器
--network # 指定网络 默认是bridge 如果需要其他需要指定 `overlay` 集群网络
--dns # 指定dns解析地址 --dns xxx
--rm # 容器停止自动删除
	
-d # 以后台方式运行
-it # 使用交互方式运行,进入容器查看内容
	-it /bin/bash # 指定shell

-p # 指定容器的端口 
	-p 主机端口:容器端口 # 常用
	-p 容器端口
	容器端口
	
-P # 随机指定端口


-v # 挂载目录
	-v path # 将容器中的 path目录随机绑定到本机上 需要使用docker inspect 容器name 查看"Mounts" 中随机分配的路径 两者路径互通
	-v 本地path:容器path # 将容器path挂载到本地path
--volumes-from # 复制容器name的卷 创建新容器 --volumes-from 容器name 

-h # 指定主机名 -h name
-e # -e后跟指令变量 用于携带参数 

-m # -m后跟内存 例如 50M 细粒度控制
--memory-swap # 必须先设置 -m 参数后才能使用这个参数 例如 -m 正数M  --memory-swap 正数S 容器的可用总空间为S,其中ram(物理内存)为M,swap(交换内存)为(S-M),若S=M则无可swap空间 // -m 正数M  --memory-swap 0 相当未设置swap(unset) 若主机启用(docer host)swap则容器可用swap为2*M // -m 正数M  --memory-swap -1      若主机启用(docer host)swap则容器可使用最大至主机上的所有swap空间的swap资源

--omm-kill-disable # 禁止omm被kill掉
--cpuset-cpus # 指定cpu执行 num也可以指定范围 1-3 表示1-3核 --cpuset-cpus num
-c # 指定cpu权重 如果不指定默认为1024 按照权重分配CPU  -c num
--cpus=<value> # 指定cpu核数 例如 --cpus="1.5" 使用1.5核

--link # 链接容器name 可以通过ping别名来ping被链接的容器ip --link 容器name:别名 
--ip # 指定ip --ip  xxx.xxx.xxx.x 	

# 当使用docker run命令创建启动容器时,Docker在后台运行的标准操作有下面几个步骤

# 1、检测本地是否存在指定的镜像,不存在就从公有仓库下载

# 2、利用镜像创建并启动一个容器

# 3、分配一个文件系统,并在只读的镜像层外面挂载一层可读写层

# 4、从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去

# 5、从地址池配置一个IP地址给容器

# 6、执行用户指定的应用程序

# 7、执行完毕后终止容器
查看容器

docker ps

$ docker ps # 查看运行的容器

# 常用可选项
  -a, --all             # 显示所有容器(默认显示为正在运行)
  -f, --filter filter   # 根据提供的条件过滤输出
  -n, --last int        # 显示最后创建的n个容器(包括所有状态)(默认为-1) -n=1 显示1个
  -l, --latest          # 显示最新创建的容器(包括所有状态)
  -q, --quiet           # 仅显示ID
  -s, --size            # 显示大小
退出容器
exit # 直接退出容器并停止
ctrl + P + Q # 容器不停止退出
control + P + Q # MAC
删除容器

docker rm

$ docker rm 容器ID # 删除指定容器

$ docker rm -f # 强制删除 包括在运行的容器

$ docker rm -f $(docker ps -aq) # 删除所有容器
$ docker ps -a -q|xargs docker rm # 删除所有容器

# 其他选项
  -f, --force     # 强项终止并删除一个运行中的容器。
  -l, --link      # 删除容器的连接,但保留容器。
  -v, --volumes   # 删除容器挂载的数据卷。
启停操作
$ docker create 容器 # 创建容器

$ docker start 容器ID # 启动容器
 
$ docker restart 容器ID # 重启容器

$ docker stop 容器ID # 停止当前正在运行的容器

$ docker kill 容器ID # 强制停止当前容器

$ docker pause 容器ID # 暂停容器

$ docker unpause 容器ID # 取消暂停

常用其他命令

查看容器内部日志

docker logs

$ docker logs [可选项] 容器ID

# 常用可选项
      --details        # 显示提供给日志的其他详细信息
  -f, --follow         # 跟踪日志输出
      --since string   Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
      --tail string    # 从日志末尾开始显示的行数(默认为“全部”)
  -t, --timestamps     # 显示时间戳
      --until string   Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
 
$ docker logs -f -t --tail 100 xxxx
查看容器内部的进程信息
$ docker top 容器ID
查看元数据

docker inspect

$ docker inspect 容器ID
进入当前正在运行的容器

docker exec

$ docker exec 容器ID 命令 # 以交互的形式在容器中执行命令 命令必须是绝对路径 例如 /bin/sh

# 其他选项
  -d, --detach               # 后台运行
  -e, --env list             # 设置环境变量
  -i, --interactive          # 交互模式
      --privileged           Give extended privileges to the command
  -t, --tty                  # 交互模式接口 打开shell
  -u, --user string          Username or UID (format: <name|uid>[:<group|gid>])
  -w, --workdir string       # 切换到工作目录

docker attach

$ docker attach 容器ID # 连接进入shell 

区别:

  • exec 进入容器后开启一个新的终端可以在里面操作
  • attach不会开启,多个连接会共享一个终端
从容器内拷贝到主机上

docker cp

$ docker cp [其他选项] 容器ID:容器内路径 目的的主机路径
$ dkcker cp [其它选项] 主机路径 容器ID:容器内路径

# 其他选项
  -a, --archive       # 存档模式(复制所有uid / gid信息)
  -L, --follow-link   # 始终遵循SRC_PATH中的符号链接
导入导出

docker export

docker export的应用场景主要用来制作基础镜像,比如你从一个ubuntu镜像启动一个容器,然后安装一些软件和进行一些设置后,使用docker export保存为一个基础镜像。然后,把这个镜像分发给其他人使用,比如作为基础的开发环境。

$ docker export [其他选项] 容器ID

# 其他选项
  -o, --output string   # 导出路径

docker import

$ docker import [其他选项] 容器文件/url

# 其它选项
  -c, --change list       # 将Dockerfile指令应用于创建的映像
  -m, --message string    # 设置导入图像的提交消息
      --platform string   # 如果服务器支持多平台,则设置平台

docker save

docker save的应用场景是,如果你的应用是使用docker-compose.yml编排的多个镜像组合,但你要部署的客户服务器并不能连外网。这时,你可以使用docker save将用到的镜像打个包,然后拷贝到客户服务器上使用docker load载入。

$ docker save [其他选项] 镜像 [镜像...]

# 其他选项
  -o, --output string   # 写入文件,而不是STDOUT

docker load

$ docker load [其他选项]

# 其他选项
  -i, --input string   # 从tar存档文件中读取,而不是从STDIN中读取
  -q, --quiet          # 抑制负载输出

docker save和docker export的区别

  1. docker save保存的是镜像(p_w_picpath),docker export保存的是容器(container);

  2. docker load用来载入镜像包,docker import用来载入容器包,但两者都会恢复为镜像;

  3. docker load不能对载入的镜像重命名,而docker import可以为镜像指定新名称。

查看构建历史

docker history

$ docker history [其他选项] 镜像ID

# 其他选项
  -H, --human           # 以人类可读的格式打印尺寸和日期(默认为true)
      --no-trunc        # 不要截断输出
  -q, --quiet           # 仅显示数字ID

网络

docker network

$ docker network 命令

# 命令:
  connect     # 将容器连接到网络
  create      # 建立网络
  disconnect  # 断开容器与网络的连接
  inspect     # 在一个或多个网络上显示详细信息
  ls          # 列出网络
  prune       # 删除所有未使用的网络
  rm          # 删除一个或多个网络
$ docker network connect [选项] 网络 容器ID

# 选项
      --alias strings           # 为容器添加网络范围的别名
      --driver-opt strings      # 网络的驱动程序选项
      --ip string               # IPv4地址(例如172.30.100.104)
      --ip6 string              # IPv6地址(例如2001:db8 :: 33)
      --link list               # 将链接添加到另一个容器
      --link-local-ip strings   # 为容器添加本地链接地址
$ docker network create [选项] 网络

# 选项
      --attachable           # 启用手动容器附件
      --aux-address map      # 网络驱动程序使用的辅助IPv4或IPv6地址(默认映射[])
      --config-from string   # 从中复制配置的网络
      --config-only          # 创建仅配置网络
  -d, --driver string        # 驱动程序来管理网络(默认为“网桥”)
      --gateway strings      # 主子网的IPv4或IPv6网关
      --ingress              # 创建集群路由网状网络
      --internal             # 限制外部访问网络
      --ip-range strings     # Allocate container ip from a sub-range
      --ipam-driver string   # IP地址管理驱动程序(默认为“默认”)
      --ipam-opt map         # 设置IPAM驱动程序特定的选项(默认映射[])
      --ipv6                 # 启用IPv6网络
      --label list           # 在网络上设置元数据
  -o, --opt map              # 设置驱动程序特定的选项(默认映射[])
      --scope string         # 控制网络范围
      --subnet strings       # 代表网段的CIDR格式的子网
$ docker network disconnect [选项] 网络 镜像ID

# 选项
  -f, --force   # 强制容器断开网络连接
$ docker network inspect [选项] 网络 [网络...]

# 选项
  -v, --verbose         # 详细输出以进行诊断
$ docker network ls [选项]

# 选项
  -f, --filter filter   # 提供过滤器值(例如'driver = bridge')
      --no-trunc        # 不要截断输出
  -q, --quiet           # 仅显示网络ID
$ docker network prune [选项]

# 选项
      --filter filter   # 提供过滤器值(例如'until = <timestamp>')
  -f, --force           # 不提示确认
$ docker network rm 网络 [网络...]

镜像

镜像是什么

镜像是一种轻量级,可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码,运行时、库、环境变量和配置文件。

所有的应用直接打包为docker镜像,直接跑起来

如何得到镜像:

  • 从远程仓库下载
  • 拷贝
  • 自己制作一个镜像(DockerFile)

Docker镜像加载原理

UnionFS(联合文件系统)

Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

Docker镜像加载原理

docker的镜像实际上是由一层一层的文件系统构成,这种层级的文件系统UnionFS。

bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M??

对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。

分层镜像

所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上创建新的镜像层。举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。

上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。 下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。 Docker通过存储引擎(新版本采用快照机制) 的方式来实现镜像层堆栈, 并保证多镜像层对外展示为统一的文件系统。 Linux上可用的存储引擎有AUFS、 Overlay2、Device Mapper、Btrfs以及ZFS。顾名思义, 每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。 Docker在Windows上仅支持windows filter一种存储引擎, 该引擎基于NTFS文件系统之上实现了分层和CoW[1] 。 下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

Docker镜像都是只读的, 当容器启动时, 一个新的可写层被加载到镜像的顶部 这一层就是我们通常说的容器层,容器之下的都叫镜像层!

commit镜像

$ docker commit [其他选项] 容器ID 新镜像名[:TAG]

$ docker commit -m="提交的描述信息" -a="作者" 容器ID 目标镜像名[:TAG]

# 其他选项
  -a, --author string    # 作者(例如,“约翰·汉尼拔·史密斯<hannibal@a-team.com>”)
  -c, --change list      # 将Dockerfile指令应用于创建的映像
  -m, --message string   # 提交讯息
  -p, --pause            # 提交期间暂停容器(默认为true)

常用镜像

scratch # 99%镜像使用的最基础镜像

容器数据卷

容器之间有一个数据共享的技术,Docker容器中产生的数据,同步到本地。

目录挂载,将我们的容器的内部,挂在到本地持久化,且容器间也是可以数据共享的

使用数据卷

  • 直接使用命令来挂载(启动容器时挂载)

    $ docker run -v 主机目录:容器内目录
    
  • 具名挂载和匿名挂载

    # 匿名挂载
    $ docker run -v 容器内目录 
    
    # 具名挂载
    $ docker run -v 卷名:容器内目录 
    
    # 查看所有 volume 的情况 这里面显示的路径是真实存在的
    $ docker volume ls
    
    # 查看volume 具名/匿名随机的路径 信息
    # 实际存放 /var/lib/docker/volumes/具名/匿名随机的路径/_data
    $ docker volume inspect 具名/匿名随机的路径
    

扩展

# 设置容器目录权限
# ro readonly 只读
# rw readwrite 可读写
# 只要看到ro就表示这个文件只能通过宿主机来操作,容器内部是无法操作的
$ docker run -v /localPath/:/path:ro 镜像
$ docker run -v /localPath/:/path:rw 镜像

DockerFile

dockerfile是用来构建docker镜像的文件,命令参数脚本

Dockerfile 指令

Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。

docker build命令用于从Dockerfile构建映像。可以在docker build命令中使用-f标志指向文件系统中任何位置的Dockerfile。

注意 []中的json数组中一定要用 " " # 双引号

docker build -f /path/to/a/   # 指定文件

docker build -t debian-jdk8:v1.0 .    
	# 其中-t debian-jdk8:v1.0表示打包的镜像名为debian-jdk,tag为v1.0(前面说过,tag是可以任意命名的,不一定要是这种格式),注意命令的最后有一个.,这个表示打包的上下文(其实就是Dockerfile所在目录)是在当前目录,然后目录下的Dockerfile就会被编译执行。

基础知识

  1. 每个保留关键字(指令)必须都是大写字母
  2. 指令从上到下顺序执行
  3. #表示注释
  4. 每一个指令都会创建提交一个新的镜像层,并提交
  5. 第一条指令必须是FORM

常用指令

FROM
FROM:指定基础镜像,必须为第一个命令
格式:
  FROM <image>
  FROM <image>:<tag>
  FROM <image>@<digest>  # digest哈希码
示例:
  FROM mysql:5.6
注:
  tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
MAINTAINER
MAINTAINER: 维护者信息 # 新版使用LABEL
格式:
    MAINTAINER <name>
示例:
    MAINTAINER Jasper Xu
    MAINTAINER sorex@163.com
    MAINTAINER Jasper Xu <sorex@163.com>
RUN
RUN:构建镜像时执行的命令
# RUN用于创建镜像容器中执行命令,其有以下两种命令执行方式:

# shell执行
格式:
    RUN <command>
多条指令推荐使用 && 连接  多Run会增加分层

# exec执行
格式:
    RUN ["executable", "param1", "param2"]
示例:
    RUN ["executable", "param1", "param2"]
    RUN apk update
    RUN ["/etc/execfile", "arg1", "arg1"]
注:
  ***RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache
ADD
ADD:将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget

格式: # 如果路径中有空白字符建议使用第二种格式
		  # src如果是目录 则会复制目录下的所有内容 而不是复制整个目录
		  # dest必须是一个目录并且以/结尾
    ADD <src>... <dest>  # src 要复制的源文件或目录,支持使用通配符 被copy的文件需要在Dockfile同级目录中  dest 目标路径,即正在创建image的文件路径 建议使用绝对路径
    
    ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
    ADD hom* /mydir/          # 添加所有以"hom"开头的文件
    ADD hom?.txt /mydir/      # ? 替代一个单字符,例如:"home.txt"
    ADD test relativeDir/     # 添加 "test" 到 `WORKDIR`/relativeDir/
    ADD test /absoluteDir/    # 添加 "test" 到 /absoluteDir/
    ADD test     # 添加 "test" 到 当前目录
CP
COPY:功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
格式:
	COPY <src>... <dest>
    COPY ["<src>",... "<dest>"] 用于支持包含空格的路径
    COPY --from=xxx / /  # 从xxx镜像内复制 如果是数字 就是第几阶段 从0开始
WORKDIR
WORKDIR:工作目录,类似于cd命令
格式:
    WORKDIR /path/to/workdir
示例:
    WORKDIR /a  (这时工作目录为/a) // 如果有进入 如果没有创建
    WORKDIR b  (这时工作目录为/a/b)
    WORKDIR c  (这时工作目录为/a/b/c)
注:
  通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
VOLUME
VOLUME:用于指定持久化目录 # 只能指定容器内的路径 不能指定宿主机的路径
格式:
    VOLUME ["/path/to/dir"]
示例:
    VOLUME ["/data"]
    VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
注:
  一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1 卷可以容器间共享和重用
2 容器并不一定要和其它容器共享卷
3 修改卷后会立即生效
4 对卷的修改不会对镜像产生影响
5 卷会一直存在,直到没有任何容器在使用它
ENV
ENV:设置环境变量
格式:
    ENV <key> <value>  #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
    ENV <key>=<value> ...  #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
示例:
    ENV myName John Doe  # myName 后 是value # 理论上ENV一次只能设置一个变量 可以通过 && 来执行多条命令
    ENV myDog Rex The Dog
    ENV myCat=fluffy
EXPOSE
EXPOSE:指定于外界交互的端口
格式:
    EXPOSE <port> [<port>...]
示例:
    EXPOSE 80 443
    EXPOSE 8080
    EXPOSE 11211/tcp 11211/udp
注:
  EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口

CMD
CMD:构建容器后调用,也就是在容器启动时才进行调用。 # 启动执行 // 如果docker执行其他命令 cmd可能会被忽略
格式:
    CMD ["executable","param1","param2"] (执行可执行文件,优先) # executable指的是以什么命令去执行后面的命令 例如["/bin/sh","-c", "echo xxx "] # 如果不使用/bin/sh 不会使用环境变量的内容
    CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
    CMD command param1 param2 (执行shell内部命令)  # 这里的command指的是shell命令 默认是/bin/sh -c 来执行 
示例:
    CMD echo "This is a test." | wc -
    CMD ["/usr/bin/wc","--help"]
注:
   CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
*** 如果存在多个CMD 只会执行最后一条且可被替代
ENTRYPOINT
 ENTRYPOINT:配置容器,使其可执行化。配合CMD可省去"application",只使用参数。
 格式:
    ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先) exec指令
    ENTRYPOINT command param1 param2 (shell内部命令) shell 格式
示例:
    FROM ubuntu
    ENTRYPOINT ["top", "-b"]
    CMD ["-c"]
注:
   ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
		 # 如果需要在外部修改ENTRYPOINT设置的指令 需要增加参数 -enterpoint string 指令
		 # 如果ENTRYPOINT 与 CMD同时存在 CMD接收到的内容用作ENTRYPOINT的参数使用 # 一般用如果ENTRYPOINT指定容器执行命令的方式
*** 可追加命令(直接加参数 例如内部写  ENTRYPOINT ["ls"] 外部run的时候 带上 "-l" 最后执行 ls -l)
ONBUILD
ONBUILD:用于设置镜像触发器
格式:
  ONBUILD [INSTRUCTION]
示例:
  ONBUILD ADD . /app/src
  ONBUILD RUN /usr/local/bin/python-build --dir /app/src
注:
   # 当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发
	 # 不能执行FROM 以及 ONBUILD指令

其他指令

LABEL
LABEL:用于为镜像添加元数据
格式:
    LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
  LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
注:
  使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
USER
USER:指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
格式:
  USER user
  USER user:group
  USER uid
  USER uid:gid
  USER user:gid
  USER uid:group

 示例:
  USER www

 注:
  使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
	# uid 必须要在/etc/passwd中某用户有效的UID否则docker run 会运行失败
	# 默认是root用户运行
HEALTHCHECK
HEALTHCHECK :检测容器是否健康
	# HEALTHCHECK参数:
		--interval=num(default:30s) # 连接时间
		--timeout=num(default:30s) # 超时时间
		--start-period=num(default:0s) # 启动容器等待检测时间
		--retries=num(default:0)
	# 返回值:
		0 seccuess
		1 unhealthy
		2 reserved
	
示例:
	HEALTHCHECK --interval=5m --timeout=3s  CMD curl -f http://localhost/ || exit 1  
		# CMD是关键字 必须加 # 成功执行 curl  http://localhost/ 失败则退出		
ARG
ARG:用于指定传递给构建运行时的变量
格式:
    ARG <name>[=<default value>]
示例:
    ARG site
    ARG build_user=www
# 在build中使用 --build-arg
	demo 
		docker build --build-arg site=xxx

推送到仓库

# 登录
docker login
		user:songzhibin
		password:xxxxxxxx
		
docker tag 镜像id 你的用户名/镜像名:版本号 # 版本号不输入默认是latest

# 推送
docker push 已经打好的tag

自建仓库

yum install docker-registry
# 主配置文件 /etc/docker-distribution/registry/config.yml
# 主程序 /usr/bin/registry
# 启动目录 /usr/lib/sysyemd/system/docker-distribution.service
# 上传镜像默认存储位置 /var/lib/registry
启动 systemctl start docker-distribution # 默认监听 5000端口 在config.yml文件中配置

# 打标签
docker tag 域名(ip):端口/仓库项目名/镜像名

# 修改标签
docker tag 旧标签 新标签
例如:
docker tag mysql:5.5 mysql:latest

# 上传 
docker push 域名/仓库项目名/镜像名

Docker网络

原理:

​ 我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个docker0桥接模式,使用的技术是 veth-pair 技术

# veth-pair 就是一对的虚拟设备接口,他们都是成对出现,一端连着协议,一端彼此相连
# 正因为有这个特性,veth-pair 充当一个桥梁,连接各种虚拟网络设备的
# docker中的所有的网络接口都是虚拟的。虚拟的转发效率高!

痛点:每次创建Docker镜像生成的IP地址不一样,如何实现容器间标记通讯

link链接(不推荐使用了)

# 通过 --link 既可以解决了网络连通问题 但是无法实现双联通
# docker run 时连接
$ docker run --name t1 --link t2  xxx # 启动 name 为 t1 链接名为 t2的容器

# link实际上是在当前容器的 hosts 中增加了一个 link后别名的映射

# 不推荐使用了
# docker0的问题,不支持容器名连接访问

自定义网络

查看所有网络
# 查看所有网络
$ docker network ls
网络模式
  • bridge:桥接(默认)
  • none:不配置网络
  • host:主机模式(和宿主机共享网络)
  • container:容器内网络连通(用得少,局限很大)
创建网络
# 默认启动时桥接模式
$ docker run 镜像
# 等价于 默认桥接的就是宿主机的 docker0网卡
$ docker run --net bridge 镜像

# docker0特点, 默认:域名不能访问, --link可以打通连接(单向)

# 自定义网络

# 创建一个Mynet网络 
# --driver 以桥接模式创建
# --subnet CIDR格式子网
# --gatewat 网关地址
$ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 Mynet

# 查看刚刚创建的网络
$ docker network ls
NETWORK ID          NAME                    DRIVER              SCOPE
213886dc30fa        Mynet                   bridge              local

# 查看我们自己创建的网络
$ docker network inspect Mynet
[
    {
        "Name": "Mynet",
        "Id": "213886dc30fa49648d55acab93f5aa8359aacfaea4a1f3a22a395537c68b3621",
        "Created": "2020-11-27T14:46:22.1600143Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

# 创建docker容器 连接自定义网络
$ docker run --net Mynet xxx

自定义网络的好处:

​ 修复了docker0的缺点 有了比 --link更好的双向联通

网络连通

$ docker network connect 网络 容器id
# 连通之后就是将容器id 放到了 指定网络中
# 一个容器两个ip

Docker Compose

安装

pip 安装

$ sudo pip install -U docker-compose

$ docker-compose -h
Define and run multi-container applications with Docker.

Usage:
  docker-compose [-f <arg>...] [options] [--] [COMMAND] [ARGS...]
  docker-compose -h|--help

Options:
  -f, --file FILE             Specify an alternate compose file
                              (default: docker-compose.yml)
  -p, --project-name NAME     Specify an alternate project name
                              (default: directory name)
  -c, --context NAME          Specify a context name
  --verbose                   Show more output
  --log-level LEVEL           Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
  --no-ansi                   Do not print ANSI control characters
  -v, --version               Print version and exit
  -H, --host HOST             Daemon socket to connect to

  --tls                       Use TLS; implied by --tlsverify
  --tlscacert CA_PATH         Trust certs signed only by this CA
  --tlscert CLIENT_CERT_PATH  Path to TLS certificate file
  --tlskey TLS_KEY_PATH       Path to TLS key file
  --tlsverify                 Use TLS and verify the remote
  --skip-hostname-check       Don't check the daemon's hostname against the
                              name specified in the client certificate
  --project-directory PATH    Specify an alternate working directory
                              (default: the path of the Compose file)
  --compatibility             If set, Compose will attempt to convert keys
                              in v3 files to their non-Swarm equivalent (DEPRECATED)
  --env-file PATH             Specify an alternate environment file

Commands:
  build              Build or rebuild services
  config             Validate and view the Compose file
  create             Create services
  down               Stop and remove containers, networks, images, and volumes
  events             Receive real time events from containers
  exec               Execute a command in a running container
  help               Get help on a command
  images             List images
  kill               Kill containers
  logs               View output from containers
  pause              Pause services
  port               Print the public port for a port binding
  ps                 List containers
  pull               Pull service images
  push               Push service images
  restart            Restart services
  rm                 Remove stopped containers
  run                Run a one-off command
  scale              Set number of containers for a service
  start              Start services
  stop               Stop services
  top                Display the running processes
  unpause            Unpause services
  up                 Create and start containers
  version            Show version information and quit

二进制包

发布的二进制包可以在 https://github.com/docker/compose/releases 找到。

下载后直接放到执行路径即可。

命令说明

大部分命令都可以运行在一个或多个服务上。如果没有特别的说明,命令则应用在项目所有的服务上。

执行 docker-compose [COMMAND] --help 查看具体某个命令的使用说明。

基本的使用格式是

docker-compose [options] [COMMAND] [ARGS...]

选项

  • --verbose 输出更多调试信息。
  • --version 打印版本并退出。
  • -f, --file FILE 使用特定的 compose 模板文件,默认为 docker-compose.yml
  • -p, --project-name NAME 指定项目名称,默认使用目录名称。

命令

build

构建或重新构建服务。

服务一旦构建后,将会带上一个标记名,例如 web_db。

可以随时在项目目录下运行 docker-compose build 来重新构建服务。

help

获得一个命令的帮助。

kill

通过发送 SIGKILL 信号来强制停止服务容器。支持通过参数来指定发送的信号,例如

$ docker-compose kill -s SIGINT
logs

查看服务的输出。

port

打印绑定的公共端口。

ps

列出所有容器。

pull

拉取服务镜像。

rm

删除停止的服务容器。

run

在一个服务上执行一个命令。

例如:

$ docker-compose run ubuntu ping docker.com

将会启动一个 ubuntu 服务,执行 ping docker.com 命令。

默认情况下,所有关联的服务将会自动被启动,除非这些服务已经在运行中。

该命令类似启动容器后运行指定的命令,相关卷、链接等等都将会按照期望创建。

两个不同点:

  • 给定命令将会覆盖原有的自动运行命令;
  • 不会自动创建端口,以避免冲突。

如果不希望自动启动关联的容器,可以使用 --no-deps 选项,例如

$ docker-compose run --no-deps web python manage.py shell

将不会启动 web 容器所关联的其它容器。

scale

设置同一个服务运行的容器个数。

通过 service=num 的参数来设置数量。例如:

$ docker-compose scale web=2 worker=3
start

启动一个已经存在的服务容器。

stop

停止一个已经运行的容器,但不删除它。通过 docker-compose start 可以再次启动这些容器。

up

构建,(重新)创建,启动,链接一个服务相关的容器。

链接的服务都将会启动,除非他们已经运行。

默认情况, docker-compose up 将会整合所有容器的输出,并且退出时,所有容器将会停止。

如果使用 docker-compose up -d ,将会在后台启动并运行所有的容器。

默认情况,如果该服务的容器已经存在, docker-compose up 将会停止并尝试重新创建他们(保持使用 volumes-from 挂载的卷),以保证 docker-compose.yml 的修改生效。如果你不想容器被停止并重新创建,可以使用 docker-compose up --no-recreate。如果需要的话,这样将会启动已经停止的容器。

清理重新编译

$ docker-compose up --buile 

环境变量

环境变量可以用来配置 Compose 的行为。

DOCKER_开头的变量和用来配置 Docker 命令行客户端的使用一样。如果使用 boot2docker , $(boot2docker shellinit) 将会设置它们为正确的值。

COMPOSE_PROJECT_NAME

设置通过 Compose 启动的每一个容器前添加的项目名称,默认是当前工作目录的名字。

COMPOSE_FILE

设置要使用的 docker-compose.yml 的路径。默认路径是当前工作目录。

DOCKER_HOST

设置 Docker daemon 的地址。默认使用 unix:///var/run/docker.sock,与 Docker 客户端采用的默认值一致。

DOCKER_TLS_VERIFY

如果设置不为空,则与 Docker daemon 交互通过 TLS 进行。

DOCKER_CERT_PATH

配置 TLS 通信所需要的验证(ca.pemcert.pemkey.pem)文件的路径,默认是 ~/.docker

YAML 模板文件

默认的模板文件是 docker-compose.yml,其中定义的每个服务都必须通过 image 指令指定镜像或 build 指令(需要 Dockerfile)来自动构建。

其它大部分指令都跟 docker run 中的类似。

如果使用 build 指令,在 Dockerfile 中设置的选项(例如:CMD, EXPOSE, VOLUME, ENV 等) 将会自动被获取,无需在 docker-compose.yml 中再次设置。

image

指定为镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试拉去这个镜像。

例如:

image: ubuntu
image: orchardup/postgresql
image: a4bc65fd
build

指定 Dockerfile 所在文件夹的路径。 Compose 将会利用它自动构建这个镜像,然后使用这个镜像。

build: /path/to/build/dir
command

覆盖容器启动后默认执行的命令。

command: bundle exec thin -p 3000

链接到其它服务中的容器。使用服务名称(同时作为别名)或服务名称:服务别名 (SERVICE:ALIAS) 格式都可以。

links:
 - db
 - db:database
 - redis

使用的别名将会自动在服务容器中的 /etc/hosts 里创建。例如:

172.17.2.186  db
172.17.2.186  database
172.17.2.187  redis

相应的环境变量也将被创建。

链接到 docker-compose.yml 外部的容器,甚至 并非 Compose 管理的容器。参数格式跟 links 类似。

external_links:
 - redis_1
 - project_db_1:mysql
 - project_db_1:postgresql
ports

暴露端口信息。

使用宿主:容器 (HOST:CONTAINER)格式或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。

ports:
 - "3000"
 - "8000:8000"
 - "49100:22"
 - "127.0.0.1:8001:8001"

注:当使用 HOST:CONTAINER 格式来映射端口时,如果你使用的容器端口小于 60 你可能会得到错误得结果,因为 YAML 将会解析 xx:yy 这种数字格式为 60 进制。所以建议采用字符串格式。

expose

暴露端口,但不映射到宿主机,只被连接的服务访问。

仅可以指定内部端口为参数

expose:
 - "3000"
 - "8000"
volumes

卷挂载路径设置。可以设置宿主机路径 (HOST:CONTAINER) 或加上访问模式 (HOST:CONTAINER:ro)。

volumes:
 - /var/lib/mysql
 - cache/:/tmp/cache
 - ~/configs:/etc/configs/:ro
volumes_from

从另一个服务或容器挂载它的所有卷。

volumes_from:
 - service_name
 - container_name
environment

设置环境变量。你可以使用数组或字典两种格式。

只给定名称的变量会自动获取它在 Compose 主机上的值,可以用来防止泄露不必要的数据。

environment:
  RACK_ENV: development
  SESSION_SECRET:

environment:
  - RACK_ENV=development
  - SESSION_SECRET
env_file

从文件中获取环境变量,可以为单独的文件路径或列表。

如果通过 docker-compose -f FILE 指定了模板文件,则 env_file 中路径会基于模板文件路径。

如果有变量名称与 environment 指令冲突,则以后者为准。

env_file: .env

env_file:
  - ./common.env
  - ./apps/web.env
  - /opt/secrets.env

环境变量文件中每一行必须符合格式,支持 # 开头的注释行。

# common.env: Set Rails/Rack environment
RACK_ENV=development
extends

基于已有的服务进行扩展。例如我们已经有了一个 webapp 服务,模板文件为 common.yml

# common.yml
webapp:
  build: ./webapp
  environment:
    - DEBUG=false
    - SEND_EMAILS=false

编写一个新的 development.yml 文件,使用 common.yml 中的 webapp 服务进行扩展。

# development.yml
web:
  extends:
    file: common.yml
    service: webapp
  ports:
    - "8000:8000"
  links:
    - db
  environment:
    - DEBUG=true
db:
  image: postgres

后者会自动继承 common.yml 中的 webapp 服务及相关环节变量。

net

设置网络模式。使用和 docker client--net 参数一样的值。

net: "bridge"
net: "none"
net: "container:[name or id]"
net: "host"
pid

跟主机系统共享进程命名空间。打开该选项的容器可以相互通过进程 ID 来访问和操作。

pid: "host"
dns

配置 DNS 服务器。可以是一个值,也可以是一个列表。

dns: 8.8.8.8
dns:
  - 8.8.8.8
  - 9.9.9.9
cap_add, cap_drop

添加或放弃容器的 Linux 能力(Capabiliity)。

cap_add:
  - ALL

cap_drop:
  - NET_ADMIN
  - SYS_ADMIN

配置 DNS 搜索域。可以是一个值,也可以是一个列表。

dns_search: example.com
dns_search:
  - domain1.example.com
  - domain2.example.com
working_dir, entrypoint, user, hostname, domainname, mem_limit, privileged, restart, stdin_open, tty, cpu_shares

这些都是和 docker run 支持的选项类似。

cpu_shares: 73

working_dir: /code
entrypoint: /code/entrypoint.sh
user: postgresql

hostname: foo
domainname: foo.com

mem_limit: 1000000000
privileged: true

restart: always

stdin_open: true
tty: true
posted @ 2020-11-28 08:36  Binb  阅读(409)  评论(0编辑  收藏  举报