[Docker] Docker 基础教程(概念/原理/基础操作)

1 概述

1.1 定义

Docker is a platform that allows you to "build ,ship ,and run any  app, anywhere. "

  • Docker是一个平台,它提供哪些服务呢?任何一台装有Docker的机器上你都可以构建发布运行你的应用程序

It has come a long way in an incredibly short time and is now considered a standard way of solving one of the costliest aspects of software: deployment.

  • Docker在很短的时间内就走得很远,如今它基本是解决软件最昂贵的环节:部署的标准解决方案

在Docker出现之前,有一堆与软件部署的工具软件,虚拟机、配置管理工具、打包管理工具、复杂的webs库依赖。所有这些工具都需要专业的工程师去管理和维护,多数软件有一套独特的配置方法。

小结:

  • Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。
    开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何支持 docker 的机器上运行。
    容器是完全使用沙箱机制,相互之间不会有任何接口调用。

  • Docker使用Google公司推出的Go语言进行开发实现,基于Linux内核的cgroupnamespace,以及AUFS类的UnionFS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。

由于隔离的进程独立于宿主机(真实机器)和其它的隔离的进程,因此也称其为容器。Docker最初实现是基于LXC

1.2 使用Docker来干什么?

比较一下Docker诞生前和诞生后软件开发的变化就能感受到Docker可以用来干嘛了。

Docker诞生标志着软件工程领域进入新纪元

1.3 为什么要使用Docker?

1.4 优缺点

1.4.1 优点

1)快
运行时的性能快,管理操作(启动,停止,开始,重启等等) 都是以秒或毫秒为单位的。
2)敏捷
像虚拟机一样敏捷,而且会更便宜,在 bare metal(裸机)上布署像点个按钮一样简单。
3)灵活
将应用和系统“容器化”,不添加额外的操作系统
4)轻量
在一台服务器上可以布署 100~1000 个 Containers 容器。
5)便宜
开源的,免费的,低成本的。

1.4.2 缺点

所有容器共用 linux kernel 资源,资源能否实现最大限度利用,所以在安全上也会存在漏洞。

1.5 版本

目前最近的2个版本

  • docker-ce
docker-ce-18.06.3.ce-3.el7
  • docker-ee

1.6 Docker 应用场景

  • Web 应用的自动化打包和发布。

  • 自动化测试和持续集成、发布。

  • 在服务型环境中部署和调整数据库或其他的后台应用。

  • 从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。

2 Docker的原理与概念

2.0 Docker的架构与模式

2.0.1 体系结构

  • VM是在宿主机器操作系统的基础上创建虚拟化的操作系统,需要重新加载一个Guest OS。
  • Docker是在宿主操作系统上运行Docker引擎,在引擎的基础上再安装应用。
  • Docker是共享宿主机的内核,有着比VM更少的抽象层。

2.0.2 部署架构/运行架构

概念 说明
Docker 镜像(Images) Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。
Docker 容器(Container) 容器是独立运行的一个或一组应用,是镜像运行时的实体。
Docker 客户端(Client) Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。
Docker 主机(Host) 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。
Docker Registry Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
Docker Machine Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。
  • Docker 使用了 client / server 的架构模式,如下图所示
  • Docker daemon 是后台总管,对外提供了REST API,当收到 Docker Client 发送的请求时,执行诸如镜像、容器、网络、存储等一系列操作

2.1 镜像(Image) ≈ 容器的静态模板

Docker的image可以理解是一个只读的静态模板,类似于我们在装系统的时候用到的.iso文件

操作系统分为内核用户空间
对于Linux而言,内核启动后,会挂载root文件系统为其提供用户空间支持。
Docker镜像Image),就相当于是一个root文件系统。

现在重新理解一下我们使用一个linux系统的过程:

我们开机时,linux内核会先启动;然后,挂载root文件系统作为用户空间;
而Docker镜像就相当于是一个root文件系统,每开一个就有了一个独立的用户空间。

2.2 容器(Container) ≈ 镜像的动态实例

container则相对而言是一个动态的instance
或说可以理解为我们装好了系统之后的某一台计算机,可以开机关机重启等等,也可以被格式化删除
如果我们想在另一台计算机上复现我这台计算机的系统,则可以ghost一个新的镜像,然后去安装(虽然这种操作通常不行,因为底层硬件的驱动可能不匹配)。

2.2.1 镜像(Image)与容器(Container)的关系

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的类,容器是镜像运行时的实体。
容器可以被创建、启动、停止、删除、暂停等 。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。
前面讲过镜像使用的是分层存储,容器也是如此。

按照Docker最佳实践的要求,容器不应该向其存储层内写入任何数据 ,容器存储层要保持无状态化
所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

所谓“绑定宿主目录”,就是在run一个container的时候使用-v命令把宿主机的存储目录映射进container。

我们可以这样理解:
  image是分层存储的,我们每做一次修改就会在原本的Image存储层上多搭一层,记录这个更改;而新搭的这层是静态、且可以持久化存储的。
  Container也是相同额存储架构,但是每次修改新搭的一层是动态的,而且并不是持久化存储的;
  当容器被remove,或者重启计算机(内存断电)之后,container没了,相应的这些容器存储层也没了。
  因此,要尽量保持容器存储层无状态化,所有的contain里产生的数据(比如container里的程序的运行结果)都要通过挂载宿主目录直接写进宿主硬盘里。

2.3 仓库(Repository) ≈ 模板仓库

2.3.1 Docker Hub 和 Docker Registry

  • Docker Hub 是一个公共的镜像注册中心,开发者可以在其中找到大量官方和社区维护的 Docker 镜像。同时,您也可以在 Docker Hub 上创建自己的账户,并上传自己构建的镜像供他人使用。

  • Docker Registry 则是 Docker 镜像的私有仓库,它允许您在自己的服务器上存储和管理镜像。企业和组织通常使用 Docker Registry 来保护和控制访问其内部构建的镜像。

最常使用的Registry公开服务是官方的Docker Hub,这也是默认的Registry,并拥有大量的高质量的官方镜像

2.3.2 Docker Registry

我们可以把构建好后的镜像(Image)上传到服务器,从而可以在任何地方使用到这个镜像。

  • 一个Docker Registry中可以包含多个仓库Repository
  • 每个仓库可以包含多个标签Tag
  • 每个标签对应一个镜像(Image)

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。
我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像
如果不给出标签,将以latest作为默认标签

2.4 Docker Container 生命周期

Docker 容器的生命周期包括以下几个关键阶段:

  • 创建(Create):基于镜像创建一个新的容器实例。
  • 启动(Start):启动已创建的容器,使其处于运行状态。
  • 运行(Run):在容器中运行应用程序,处理请求等。
  • 停止(Stop):停止正在运行的容器,但并不会删除它。
  • 删除(Delete):从主机系统中删除已停止的容器实例。
  • 监控(Monitor):监控容器的运行状态和资源使用情况。

3 docker的基本用法

3.0 docker服务管理

3.0.1 查看安装信息(CENTOS7)

whereis docker

which docker

3.0.2 版本信息

docker version

3.0.3 服务启停(CENTOS7)

systemctl start docker

systemctl status docker

3.0.4 开启自启(CENTOS7)

systemctl enable docker

3.1 镜像操作

创建镜像

  • 创建镜像

Docker build 是一个 Docker 命令,用于构建 Docker 镜像

docker build [OPTIONS] PATH | URL | -
  • -f,--file 指定Dockerfile文件的路径。不指定时,默认会读取上下文路径下的 dockerfile
  • -t,--tag 指定构建的镜像名和 tag。例如,构建的镜像指定多个 tag:docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
  • --add-host 可以使用一个或多个 --add-host 标志将其他主机添加到容器的 /etc/hosts 文件中。如:docker build --add-host=docker:10.180.0.1 .
  • --no-cache 构建镜像时不使用缓存
  • --network 在构建过程中为 RUN 指令设置网络模式

更多参数可以看官方文档: https://docs.docker.com/engine/reference/commandline/build/

[case 1] 使用当前目录的 Dockerfile 创建镜像,标签为 runoob/ubuntu:v1
format: docker build -t <image_name>[:<tag, defaultValue=latest>] .

docker build -t runoob/ubuntu:v1 . 

[case 2] 使用URL github.com/creack/docker-firefox 的 Dockerfile 创建镜像

docker build github.com/creack/docker-firefox

[case 3] 可以通过 -f Dockerfile 文件的位置:

$ docker build -f /path/to/a/Dockerfile .

[case 4] 在 Docker 守护进程执行 Dockerfile 中的指令前,首先会对 Dockerfile 进行语法检查,有语法错误时会返回:

$ docker build -t test/myapp .
Sending build context to Docker daemon 2.048 kB
Error response from daemon: Unknown instruction: RUNCMD

从 dockerhub 查找镜像

  • 方法1:基于 dockerhub 官网 或 github dockerhub 官方镜像库 【推荐】

这样能搜索支持的具体版本有哪些、使用文档、注意事项等 (以 mysql 镜像为例)

https://hub-stage.docker.com/_/mysql
https://github.com/docker-library/mysql/blob/3288a66368f16deb6f2768ce373ab36f92553cfa/5.7/Dockerfile

https://github.com/docker-library/docs/tree/master/mysql

  • 方法2: search 命令行方式: docker search [options] {某个镜像的名称}
  • 查找对应DockerHub仓库中的镜像
  • --filter=stars=50 : 列出收藏数不小于指定值的镜像
docker search tomcat
...
docker search centos

解释说明:

  • NAME: 镜像仓库源的名称
  • DESCRIPTION: 镜像的描述
  • OFFICIAL: 是否docker 官方发布
  • stars: 类似Github 里面的star,表示点赞、喜欢的意思。AUTOMATED: 自动构建。

补充

[root@guoweixin ~]# docker search --help
Usage: docker search [OPTIONS] TERM
Search the Docker Hub for images
Options:
-f, --filter filter Filter output based on conditions provided
根据提供的条件过滤器输出
--format string Pretty-print search using a Go template
⽤Go模板打印出漂亮的搜索结果
--limit int Max number of search results (default 25)
搜索结果的最⼤数量(默认值为25)
--no-trunc Don't truncate output
不要截断输出

下载镜像

docker pull [选项] [Docker Registey 地址[:端口号]/] 仓库名[:标签]
从 Docker 镜像仓库获取镜像

  • Docker 镜像仓库地址: 地址的格式一般是 < 域名 /IP>[: 端口号 ] 。默认地址是 Docker Hub
  • 仓库名:这里的仓库名是两段式名称, 即 < 用户名 >/< 软件名 > 。对于 Docker Hub ,如果不给出用户名,则默认为 library ,也就是官方镜像。
docker pull centos

又例如:我们需要一个tomcat的镜像来作为我们的web服务。通过 docker pull获取镜像

docker pull tomcat:版本号 //不写 :版本号 代表laster版本

查看本地镜像

要想列出已下载下来的镜像,可以使用 docker image ls 命令
列表包含了 仓库名、标签、镜像 ID、创建时间 以及 所占用的空间。

其中,仓库名、标签在之前的基础概念已经介绍过了。
镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个标签。
因此,如果拥有相同的 ID,因为它们对应的是同一个镜像。

docker images
  • -a--all,列出所有镜像
  • -q--quiet,只显示镜像的id
  • --digests: 显示镜像的摘要信息

REPOSITORY 镜像的仓库源
TAG        镜像的标签
IMAGE ID   镜像的 ID
CREATED    镜像创建时间
SIZE       镜像大小

同一个仓库源可以有多个 TAG,代表这个仓库源的不同版本,我们使用REPOSITORY:TAG 定义不同的镜像;
如果你不定义镜像的标签版本,docker将默认使用 lastest 镜像!

将镜像做成离线压缩包/将Docker镜像导出到本地

  • 将Docker镜像导出到本地

format: docker save -o <保存路径/文件名.tar> <镜像名:标签>

docker save -o centos.tar.gz centos
ls ./

加载镜像到本地Docker引擎

  • 将Docker镜像加载到本地Docker引擎中

format: docker load -i <path to image tar file>

  • 其中-i参数指定要加载的镜像tar文件的路径
docker load -i centos.tar.gz

更新容器

  • docker update 命令可以用于更新一个或多个 Docker容器配置。该命令后面的 CONTAINER 可以是容器Id,或是容器名

您可以使用此命令来防止容器消耗 Docker 主机的过多资源。使用单个命令,您可以对单个容器或多个容器进行限制。要指定多个容器,请提供以空格分隔的容器名称或 ID 列表。

  • 语法格式
# docker update [OPTIONS] CONTAINER [CONTAINER...]

注:Windows 容器不支持 docker update 命令

  • 命令参数
    | 参数 | 描述 |
    | -------------- | -------------- |
    | --cpu-rt-runtime | 将CPU实时运行时间限制在微秒级 |
    | --cpu-rt-period | 限制CPU实时周期(以微秒为单位) |
    | --cpu-quota | 限制CPU CFS(完全公平调度程序)配额 |
    | --cpu-period | 限制CPU CFS(完全公平调度程序)周期 |
    | --blkio-weight | 块 IO(相对权重),介于 10 到 1000 之间,或 0 禁用(默认 0) |
    | --cpu-shares,-c | 更新 cpu-shares。 |
    | --cpus | cpu数量 |
    | --cpuset-cpus | 允许执行的 CPU (0-3, 0,1) |
    | --cpuset-mems | 允许执行的 MEM (0-3, 0,1) |
    | --kernel-memory | 更新内核内存限制。 |
    | --memory,-m | 更新内存限制。 |
    | --memory-reservation | 内存软限制 |
    | --memory-swap | 交换限制等于内存加交换:-1 启用无限制交换 |
    | --pids-limit | API 1.40+ 调整容器 pid 限制(设置 -1 表示无限制) |
    | --restart | 更新重启策略。(容器退出时应用的重新启动策略) |

  • 案例:更新 cpu-shares

使用 docker create -it 命令,创建一个 dokcer 容器。

# docker create -it --name cnter centos
efb5ecbf143c4e1a7e62c0d7d55a4d271923c5e37148837d3b11ae23ad886d40

使用 docker update 命令,更新容器的 cpu-shares。

# docker update --cpu-shares 512 cnter

使用 docker killdocker rm 命令,删除所有容器。

docker kill `docker ps -qa` ; docker rm `docker ps -aq`
  • 案例:更新内存限制

使用 docker create -it 命令,创建一个 dokcer 容器。

docker create -it --name cnter centos
efb5ecbf143c4e1a7e62c0d7d55a4d271923c5e37148837d3b11ae23ad886d40

使用 docker update 命令,更新容器的内存限制。

docker update -m 512M cnter 

使用 docker kill 和 docker rm 命令,删除所有容器。

docker kill `docker ps -qa` ; docker rm `docker ps -aq`
  • 案例

要将容器的 cpu 份额限制为 512,请首先确定容器名称或 ID。您可以使用 docker ps 来查找这些值。您还可以使用从命令返回的 ID docker run 。然后,执行以下操作:

docker update --cpu-shares 512 abebf7571666
  • 案例

要更新多个容器的多个资源配置:

$ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse

删除镜像

  • 根据镜像的 ID 或名称删除指定镜像

format: docker rmi <镜像ID 或 名称>

docker rmi -f centos:latest

3.2 容器操作

创建 + 运行容器(run)

  • 命令格式
docker [container] run [OPTIONS] IMAGE [COMMAND] [ARG...]

Usage: Run a command in a new container
意译:通过run命令创建一个新的容器(container)
注:container参数可省略之

  • 常用选项说明
  • -d, --detach=false, 指定容器运行于前台还是后台,默认为false
  • -i, --interactive=false, 打开STDIN,用于控制台交互
  • -t, --tty=false, 分配tty设备,该可以支持终端登录,默认为false

-itd : 以交互模式(i)运行容器,支持命令交互(i)、支持终端登录(t)、容器以后台方式(d)运行

  • -u, --user="", 指定容器的用户
  • -a, --attach=[], 登录容器(必须是以docker run -d启动的容器)
  • -w, --workdir="", 指定容器的工作目录
  • -c, --cpu-shares=0, 设置容器CPU权重,在CPU共享场景使用
  • -e, --env=[], 指定环境变量,容器中可以使用该环境变量
  • -m, --memory="", 指定容器的内存上限
  • -P, --publish-all=false, 指定容器暴露的端口
  • -p, --publish=[], 指定容器暴露的端口
  • -h, --hostname="", 指定容器的主机名
  • -v, --volume=[], 给容器挂载存储卷,挂载到容器的某个目录
  • --volumes-from=[], 给容器挂载其他容器上的卷,挂载到容器的某个目录
  • --cap-add=[], 添加权限,权限清单详见:http://linux.die.net/man/7/capabilities
  • --cap-drop=[], 删除权限,权限清单详见:http://linux.die.net/man/7/capabilities
  • --cidfile="", 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法
  • --cpuset="", 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU
  • --device=[], 添加主机设备给容器,相当于设备直通
  • --dns=[], 指定容器的dns服务器
  • --dns-search=[], 指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件
  • --entrypoint="", 覆盖image的入口点
  • --env-file=[], 指定环境变量文件,文件格式为每行一个环境变量
  • --expose=[], 指定容器暴露的端口,即修改镜像的暴露端口
  • --link=[], 指定容器间的关联,使用其他容器的IP、env等信息
  • --lxc-conf=[], 指定容器的配置文件,只有在指定--exec-driver=lxc时使用
  • --name="", 指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
  • --net="bridge", 容器网络设置:
  • bridge 使用docker daemon指定的网桥
  • host //容器使用主机的网络
  • container:NAME_or_ID >//使用其他容器的网路,共享IP和PORT等网络资源
  • none 容器使用自己的网络(类似--net=bridge),但是不进行配置
  • --privileged=false, 指定容器是否为特权容器,特权容器拥有所有的capabilities
  • --restart="no", 指定容器停止后的重启策略:
  • no:容器退出时不重启
  • on-failure:容器故障退出(返回值非零)时重启
  • always:容器退出时总是重启
  • --rm=false, 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)
  • --sig-proxy=true, 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理

  • 示例
  • 运行一个在后台执行的容器,同时,还能用控制台管理:
docker run -i -t -d ubuntu:latest
  • -i--interactive,以交互模式运行容器,并保持终端激活。

注:交互就是用户输入命令,机器执行命令,并提供返回结果。那么在哪里输入命令呢?得有一个终端吧,所以这个命令必须与 -a-t 命令配合使用。
-a 选项用于指定将容器的标准输出连接到终端。使用 -t 选项创建的容器会分配一个伪终端,并将容器的标准输入、输出和错误连接到该终端。

  • -t--tty:为容器分配一个伪终端。

补充(网友观点,尚未验证): docker exec -it ... 中的 -it 参数和 docker run -it 中相同。
docker exec 中的 -it 不会受 docker run 的参数影响。他们是两个工具,只要 docker run 把容器启动了,docker exec 执行什么命令是它的事。

  • 创建、并运行容器,同时在镜像内执行shell命令
# ↓ 仅用于调试 (用于容器运行后,通过 docker logs baili-web 来查验镜像内 /app 的目录结构)
# docker run -it --name xxxx-web -d -p 8003:3003 xxxx-web:latest /bin/sh -c "ls -la /app"
  • 运行一个带命令在后台不断执行的容器,不直接展示容器内部信息:
docker run -d ubuntu:latest ping www.docker.com
  • 运行一个在后台不断执行的容器,同时带有命令,程序被终止后还能重启继续跑,还能用控制台管理:
docker run -d --restart=always ubuntu:latest ping www.docker.com
  • 为容器指定一个名字
docker run -d --name=ubuntu_server ubuntu:latest
  • 容器暴露80端口,并指定宿主机80端口与其通信(: 之前是宿主机端口,之后是容器需暴露的端口)
docker run -d --name=ubuntu_server -p 80:80 ubuntu:latest
  • 指定容器内目录与宿主机目录共享(: 之前是宿主机文件夹,之后是容器需共享的文件夹)
docker run -d --name=ubuntu_server -v /etc/www:/var/www ubuntu:latest

操纵容器/容器内执行命令(exec)

  • 官方文档

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

  • docker exec命令用于在运行中的容器内执行命令。

使用docker exec命令可以无需进入容器,在容器内执行命令,方便管理复杂多容器环境。

  • 语法
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

说明:

  • OPTIONS:可选项,用于指定一些选项,具体可以查看docker exec --help命令获取;
  • CONTAINER:必选项,指定容器名称或容器ID;
  • COMMAND:必选项,指定要在容器内执行的命令;
  • ARG:可选项,指定命令要使用的参数。

常用选项:

  • -i,--interactive:以交互模式运行容器。
  • -t,--tty:为容器分配一个虚拟终端/tty。
  • -d,--detach:在后台模式下运行容器。
  • -u,--user[=""]:以指定的用户名或UID运行容器中的命令。
  • -w,--workdir=" ":指定命令的工作目录。
  • 举例:
  • 【综合案例】在宿主机中执行 mysql 容器 的 命令
  • 方法1
docker exec -it mysql bash
> mysql -uroot -p${MYSQL_ROOT_PASSWORD} --port=3306 -h127.0.0.1 -e 'show databases;'
> exit
  • 方法2:
docker exec -it mysql sh -c "mysql -uroot -p${MYSQL_ROOT_PASSWORD} --port=3306 -h127.0.0.1 -e 'show databases;'"

注: MYSQL_ROOT_PASSWORD 也是 mysql container 内的内置环境变量

  • 执行一个交互式的bash终端:
docker exec -it container_name bash

docker exec -it container_name /bin/bash
  • 执行一个命令:
docker exec container_name ls -a

docker exec container_name /path/to/my_script.sh
  • 在后台模式下执行命令:
docker exec -d container_name ls -a
  • 在指定用户下执行命令:
docker exec -u user_name container_name ls -a
  • 指定命令工作目录:
docker exec -w /usr/src/myapp container_name ls -a
  • 容器间通信
    我们可以使用 docker exec -it 命令在不同的容器之间进行通信。例如,假设我们有两个容器 container1container2 ,我们可以通过以下命令在 container1 中执行一个命令,并将结果发送到 container2 :
docker exec -it container1 sh -c "echo 'Hello' > /tmp/message.txt"

docker exec -it container2 cat /tmp/message.txt

总结:docker exec命令是一个很好的容器管理工具,使用起来非常简单方便。掌握这个命令可以更好地管理容器的生命周期和维护运行环境。

查看容器

  • 查看容器
# 查看运行中的容器
docker [container] ps 

# 查看全部容器
docker [container] ps -a

注:container参数可省略之

输出详情介绍:

  • CONTAINER ID: 容器 ID。
  • IMAGE: 使用的镜像。
  • COMMAND: 启动容器时运行的命令。
  • CREATED: 容器的创建时间。
  • STATUS: 容器状态。

状态有7种:

  • created(已创建)
  • restarting(重启中)
  • running 或 Up(运行中)
  • removing(迁移中)
  • paused(暂停)
  • exited(停止)
  • dead(死亡)
  • PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
  • NAMES: 自动分配的容器名称。

查看容器的COMMAND详情

在显示容器列表的命令后面加上--no-trunc(大意:不省略)

docker ps -a --no-trunc

查看容器的运行日志

  • 查看日志
    在宿主主机内使用 docker logs <containerId> 命令,查看容器内的标准输出:
root@xxx:~$ docker logs 2b1b7a428627
root@xxx:~$ docker logs nginx
  • 实时查看/跟踪日志
docker logs -f nginx
  • 实时查看/跟踪最近的10条日志
docker logs -f --tail {lineNum} {containerName/containerId}
  • 查看最近XX分钟的日志
docker logs --since {xxm} {containerName/containerId}

如最近1分钟:docker logs --since 1m nginx
  • 查看指定日期至今的所有日志
如:查看2023-01-16至今的所有日志
docker logs -f --since "2023-01-16" nginx

启动/停止容器

  • 启动停止容器

format: docker start/stop {containerName | containerId}

停止容器(stop container),并不意味着容器物理上不存在了,其实它依旧存在。如果此时,新建同名容器时,将报类似如下错误:

docker: Error response from daemon: Conflict. The container name "/mysql" is already in use by container "c08e6zzzzd274e5fxxxxcb883d55f3yyyy5b54efff". You have to remove (or rename) that container to be able to reuse that name.


  • demo
docker stop nginx

删除容器

  • 删除容器

如果容器为运行状态,则:需停止容器成功后才能被成功删除

# 删除指定的容器
docker rm [-f] <containerid|containerName>

# 删除未启动成功的容器
docker rm $(docker ps -a|grep Created|awk '{print $1}')
或
docker rm $(docker ps -qf status=created)

# 删除退出状态的容器
docker rm $(docker ps -a|grep Exited|awk '{print $1}')
或
docker rm $(docker ps -qf status=exited)

# 删除所有未运行的容器
# 注:正在运行的删除不了,所有未运行的都被删除了
docker rm $(docker ps -a -q) 
或
# 注:Docker 1.13版本以后,可以使用 docker containers prune 命令,删除孤立的容器 (prune ,修剪之意)
docker container prune 

查看容器(元)信息(inspect)

docker inspect <containerName|containerId>

docker inspect [OPTIONS] NAME|ID [NAME|ID...]
  -f	指定返回值的模板文件
  -s	如果类型为容器,则显示文件总大小
  --type	返回指定类型的JSON

  • 案例
# 获取容器 IP
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $CONTAINER_ID

# 获取IP地址
docker inspect tomcat7 | grep IPAddress

# 获取日志路径
docker inspect --format='{{.LogPath}}' $CONTAINER_ID

卷标管理(volume)

# 新增卷标
docker volume create my-vo

# 查看所有卷标
docker volume ls

# 查看批量的卷标 
docker volume ls | grep mysql

# 查看具体的volume对应的真实地址
docker volume inspect my-vo

# 删除卷标
docker volume rm my-vol

容器与主机间的数据拷贝(cp)

  • 语法
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

OPTIONS说明:

  • -L : 保持源目标中的链接
  • 案例1:将主机/www/a 目录拷贝到容器96f7f14e99ab的/www目录下
docker cp /www/a 96f7f14e99ab:/www/
  • 案例2:将主机/www/a目录拷贝到容器96f7f14e99ab中,目录重命名为www
docker cp /www/a 96f7f14e99ab:/www
  • 案例3:将容器96f7f14e99ab的/www目录拷贝到主机的/tmp目录中
docker cp  96f7f14e99ab:/www /tmp/
//docker cp mysql:/var/log/mysqld.log /opt/mysql/log/mysqld.log
//docker cp mysql:/var/lib/mysql /opt/mysql/data
//docker cp mysql:/etc/mysql/conf.d /opt/mysql/conf
//docker cp mysql:/etc/my.cnf /opt/mysql

3.3 Docker 仓库管理

  • 仓库(Repository)是集中存放镜像的地方。

3.3.1 Docker Hub(官方公共仓库)

目前 Docker 官方维护了一个公共仓库 ·Docker Hub·。
大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。

  • Step1 注册

https://hub.docker.com 免费注册一个 Docker 账号。

  • Step2 登录和退出

登录需要输入用户名和密码,登录成功后,我们就可以从 docker hub 上拉取自己账号下的全部镜像。

$ docker login

  • Step3 退出

退出 docker hub 可以使用以下命令:

$ docker logout
  • Step4 拉取镜像

你可以通过 docker search 命令来查找官方仓库中的镜像,并利用 docker pull 命令来将它下载到本地。

以 ubuntu 为关键词进行搜索:

$ docker search ubuntu

  • Step4 使用 docker pull 将官方 ubuntu 镜像下载到本地:
$ docker pull ubuntu 

  • Step5 推送镜像

用户登录后,可以通过 docker push 命令将自己的镜像推送到 Docker Hub。
以下命令中的 username 请替换为你的 Docker 账号用户名。

$ docker tag ubuntu:18.04 username/ubuntu:18.04
$ docker image ls

REPOSITORY      TAG        IMAGE ID            CREATED           ...  
ubuntu          18.04      275d79972a86        6 days ago        ...  
username/ubuntu 18.04      275d79972a86        6 days ago        ...  
$ docker push username/ubuntu:18.04
$ docker search username/ubuntu

NAME             DESCRIPTION       STARS         OFFICIAL    AUTOMATED
username/ubuntu

3.4 Docker Dockerfile

3.4.1 什么是 Dockerfile?

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

DockerFileDocker的一个配置文件,本质上来说它只是一个文本文件,它是用来构建【Docker镜像】的。
DockerFile配置文件中包含了一系列的指令配置信息,用于描述如何构建镜像以及如何运行容器。
通过编写 Dockerfile,我们可以将构建 Docker 镜像的【过程】自动化,实现应用程序的快速部署迭代

3.4.2 Dockerfile的基本结构

  • Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。一般而言,Dockerfile,分为四部分:
  • 基础镜像信息;
  • 维护者信息;
  • 镜像操作指令;
  • 和容器启动时执行指令

例如:

# This Dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# Base image to use, this must be set as the first line
FROM ubuntu
# Maintainer: docker_user <docker_user at email.com> (@docker_user)
MAINTAINER docker_user docker_user@email.com
# Commands to update the image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/
sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# Commands when creating a new container
CMD /usr/sbin/nginx

其中,一开始必须指明【所基于的镜像名称】,接下来一般是说明维护者信息,后面则是镜像操作指令,例如 RUN 指令,RUN 指令将对镜像执行跟随的命令。每运行一条 RUN 指令,镜像就添加新的一层,并提交。最后是 CMD 指令,用来指定运行容器时的操作命令。

3.4.3 Dockerfile 如何编写与使用?(详解)

3.4.x Dockerfile/DockerComposeYml中Service的expose和ports的区别

  • 背景描述

形如: 对宿主机开放 3307 端口,容器内部使用 3306 端口的 mysql container:

# docker-compose.yml
...
services:
  mysql:
    container_name: openmetadata_mysql
    image: docker.getcollate.io/openmetadata/db:1.3.0
    command: "--sort_buffer_size=10M"
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
    expose:
      - 3306
    ports:
      - "3307:3306"
    volumes:
     - ./docker-volume/db-data:/var/lib/mysql
    networks:
      - app_net
    healthcheck:
      test: mysql --user=root --password=$$MYSQL_ROOT_PASSWORD --silent --execute "use openmetadata_db"
      interval: 15s
      timeout: 10s
      retries: 10

...
  • 解释/辨析:
  • exposeports在Docker中都用于容器的网络配置,但它们的用途和方式略有不同。
  • expose : 这是Dockerfile的指令,用于在创建镜像时声明容器打算使用的端口。它是对构建服务的人的一种文档性的声明,意味着运行的容器会监听某个端口。然而,只有当容器启动时使用了-P(大写)或-p(小写)参数,这些端口才会在主机上映射。此外,EXPOSE不会让容器的端口对外界可见。
  • ports: 这是docker-compose.yml文件中的一个字段,用于定义容器的端口映射。这实际上在主机上打开了端口,使得外部世界可以访问到容器的网络服务。它的格式通常为 :。例如,如果你想在主机的8080端口上运行一个在80端口上运行的web服务器,你可以使用ports配置如下:- "8080:80"。

总的来说,expose主要用于在构建阶段声明容器需要使用的端口,而ports主要用于在运行阶段定义主机和容器之间的端口映射关系

形如: ports 3307:3306 , 是指 宿主机的端口(3307)映射到容器的端口(3306)

  • 参考文献

4 综合应用场景

4.1 docker 环境下,设置容器自动启动

  • 方法1:使用 docker run 命令运行时

增加 --restart=always 参数即可

  • 方法2:使用 docker-compose 命令运行时

在 yml 文件中,需要自启动的 service 下

增加 restart: always 项目即可

  • 方法3:已运行的容器修改其自启动策略

执行命令:

  • docker update --restart=always {容器名或容器ID}
  • docker container update --restart=【容器策略】 容器名称
容器策略:
       # no 容器退出时不重启容器
       # on-failure 只有在非零状态退出时才重新启动容器
              --restart=on-failure:【重启次数】
       # always 无论退出状态如何都

K FAQ/问题集

Q1 配置docker镜像加速器?

  • Step1 登陆阿里云镜像仓库

https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
如果没有开通,可开通阿里云的镜像服务

编辑/etc/docker/daemon.json

  • Step2 重启docker
systemctl daemon-reload
systemctl restart docker

Q2 docker hub官网进不去?

问题分析

docker hub进不去是因为“hub.docker.com”是在国外的,所以访问速度很慢,导致无法访问该网址。

https://hub.docker.com/

解决方法

  • 1、找到“daemon.json”文件
  • 2、使用vim命令将其打开
  • 3、添加“{ "registry-mirrors" :["https://docker.mirrors.ustc.edu.cn"]}”内容
  • 4、重启docker即可

参考文献

Q3 怎么理解docker中的registry(注册表) 和repository(仓库)?

  • Registry:(英译:注册表、登记处)

A service responsible for hosting and distributing images. The default registry is the Docker Hub.
Docker registry 能够被第三方组织host,作为共有或者私有的registry,下面就是一些registries:

  • Repository:(英译:仓库)

A collection of related images (usually providing different versions of the same application or service).

相关映像的集合(通常提供相同应用程序或服务的不同版本)。
Docker repository is a collection of different docker images with same name, that have different tags.
Docker存储库是不同Docker映像的集合,具有相同的名称,具有不同的标签。
也就是说repository是关于同一种镜像(如python)的不同版本”tag“的“集合地”,例如 https://hub.docker.com/r/library/python/tags/。这里有许多不同tag的官方python镜像,官方python repository中所有的版本都位于Docker hub这个registry内!

  • Tag:(英译:标签)

An alphanumeric identifier (字母数字的标志符)attached to images within a repository (e.g., 14.04 or stable ).
对于 [image name] = [repository] : [tag] ,其中的“repository”是对镜像而言,某一个镜像可以有好多的tag。
所以有一种“仓库”的概念在里面,看某些书的时候会发现,有这样的的语句“每个repository可以有多个tag”。
有过创建自己的私有registry经历的就会知道,我们会重新“命名”我们的本地的image,例如:myregistryhost:5000/namespace/repo-name:tag;
此外,我们在docker hub 上面上传自己的docker 镜像的时候也会填上自己的 namespace(用户名),即你在docker hub上面注册的账号。

Y 推荐资源

Y.1 核心资源/核心链接

  • Docker 官网主页

https://www.docker.com
https://docs.docker.com/

  • Docker 官方博客:

https://blog.docker.com/

  • Docker 官方文档:

https://docs.docker.com/

  • Docker github

https://hub.docker.com
https://hub-stage.docker.com
https://github.com/moby/moby 【Docker 源代码仓库】
https://docs.docker.com/release-notes/ 【Docker 发布版本的历史】

  • Dockerhub 镜像站官网

https://hub-stage.docker.com/
https://registry.hub.docker.com

  • Docker 官方 registry 镜像加速

https://dashboard.daocloud.io/mirror

  • Docker Store:

https://store.docker.com

  • Docker Cloud:

https://cloud.docker.com

  • Docker 常见问题:

https://docs.docker.com/engine/faq/

  • Docker 远端应用 API:

https://docs.docker.com/develop/sdk/

Y.2 Docker Hub 镜像加速器列表

  • Docker 官方镜像

https://hub.docker.com/

镜像加速器 镜像加速器地址URL 专属加速器 其他加速
Docker 中国官方镜像站 https://registry.docker-cn.com ... Docker Hub
Dao Cloud 镜像站 http://f136db2.m.daocloud.io/
https://www.daocloud.io/mirror#accelerator-doc
可登录,系统分配 Docker Hub
Azure 中国镜像站 https://dockerhub.azk8s.cn Docker Hub / GCR / Quay
科大镜像站 https://docker.mirrors.ustc.edu.cn ... Docker Hub / GCR / Quay
阿里云 https://docker.mirrors.ustc.edu.cn 需登录,系统分配 Docker Hub
七牛云 https://reg-mirror.qiniu.com ... Docker Hub / GCR / Quay
网易云 https://hub-mirror.c.163.com ... Docker Hub
腾讯云 https://mirror.ccs.tencentyun.com ... Docker Hub
ustc 镜像 https://docker.mirrors.ustc.edu.cn ... --

Y.3 其他

https://cr.console.aliyun.com/cn-hangzhou/instances/artifact

X 参考文献

待阅读

posted @ 2023-05-29 01:26  千千寰宇  阅读(195)  评论(1编辑  收藏  举报