概述

docker是一门容器化技术。

Docker是一个用于开发、发布和运行应用程序的开放平台。Docker能够将应用程序与基础架构分离,以便快速交付软件。使用Docker,可以用与管理应用程序相同的方式管理基础设施。通过利用Docker快速发布、测试和部署代码的方法,您可以显著减少编写代码和在生产中运行代码之间的延迟。

Dockerfile镜像安装ssh docker装载镜像_linux

Docker 使用客户端-服务器架构。Docker客户端与 Docker守护进程对话,后者负责构建、运行和分发 Docker 容器的繁重工作。Docker 客户端和守护程序可以 在同一系统上运行,或者您可以将 Docker 客户端连接到远程 Docker 守护程序。Docker 客户端和守护程序使用 REST API,通过 UNIX 套接字或网络接口进行通信。另一个 Docker 客户端是 Docker Compose,它允许您使用由一组容器组成的应用程序。

安装

  • 安装过docker环境,先清除历史安装
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
  • 设置镜像仓库,提供稳定yum软件源。先安装yum-utils(提供yum-config-manager), 然后设置仓库。
yum install -y yum-utils

yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
  • 安装latest version的docker引擎
yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  • 启动docker
systemctl start docker
  • 验证docker引擎是否正确安装
docker run hello-world

出现下面内容则docker正确安装成功

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:

1. The Docker client contacted the Docker daemon.
1. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
1. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
1. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
[https://hub.docker.com/](https://hub.docker.com/)

For more examples and ideas, visit:
[https://docs.docker.com/get-started/](https://docs.docker.com/get-started/)

镜像

Docker容器运行是基于镜像,所以运行前需要本地存在对应镜像,如果镜像不存在,Docker会尝试先从默认镜像仓库下载(默认使用Docker Hub 公共注册服务器上的仓库),也可以通过配置使用自定义镜像仓库。

拉取镜像
# NAME为镜像名称,[]内为可选命令 TAG为镜像版本标签 
docker [image] pull NAME[:TAG]
# 简写
docker pull NAME
  • 如果不指定具体的TAG,即镜像版本。则拉取latest版本的镜像
查看镜像信息

显示已拉取镜像列表

docker images
或
docker image ls
  • 执行命令列出镜像信息显示
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    feb5d9fea6a5   8 months ago   13.3kB
  • REPOSITORY:源于哪个系列基础镜像;
  • TAG:镜像版本信息;
  • IMAGE ID:镜像ID,如果两个镜像ID相同,说明指向同一个镜像,具备不同标签名而已;
  • CREATED:镜像最后的更新时间;
  • SIZE:镜像的体积大小;

可选参数:

docker images [options]
  • -a ,–all:列出所有(包含临时文件)镜像文件;
  • -q , --quiet:仅输出镜像ID信息;
  • –digests :显示摘要信息;
  • -f, --filter :根据提供的条件过滤,"key=value"形式,多个条件要用–filter “key1=value1” --filter “key2=value2”;
dangling:显示标记为空的镜像,true和false;
label:根据标签进行过滤,其中lable的值,是docker在Dockerfile中配置的;
before:根据时间来进行过滤,表示镜像构建时间之前的镜像;
since:根据时间来进行过滤,表示在镜像构建之后的镜像;
reference:正则表达式匹配;
  • –format string :格式化输出显示;
  • –no-trunc :不截断显示输出;

查看镜像详情

docker [image] inspect NAME[:TAG]

获取镜像的详细信息,包括作者、适应架构、各层的数字摘要等。

[
    {
        "Id": "sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412",
        "RepoTags": [
            "hello-world:latest"
        ],
        "RepoDigests": [
            "hello-world@sha256:80f31da1ac7b312ba29d65080fddf797dd76acfb870e677f390d5acba9741b17"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2021-09-23T23:47:57.442225064Z",
        "Container": "8746661ca3c2f215da94e6d3f7dfdcafaff5ec0b21c9aff6af3dc379a82fbc72",
        "ContainerConfig": {
            "Hostname": "8746661ca3c2",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"/hello\"]"
            ],
            "Image": "sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "20.10.7",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/hello"
            ],
            "Image": "sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 13256,
        "VirtualSize": 13256,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/b6123f4ac2c12c46b2eb736102a38473d60b49c3de63dd86c10a3052985bb981/merged",
                "UpperDir": "/var/lib/docker/overlay2/b6123f4ac2c12c46b2eb736102a38473d60b49c3de63dd86c10a3052985bb981/diff",
                "WorkDir": "/var/lib/docker/overlay2/b6123f4ac2c12c46b2eb736102a38473d60b49c3de63dd86c10a3052985bb981/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]
重命名镜像
# NAME要重命名的镜像名称 TAG为镜像版本标签
# NEW_NAME为重命名后的镜像名称 NEW_TAG为重命名指定的新镜像版本标签
docker tag NAME[:TAG] NEW_NAME[:NEW_TAG]

例子:重命名hello-world镜像,指定镜像名称必须都是小写的。

docker tag hello-world:latest my-hello:1.0.0
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
my-hello      1.0.0     feb5d9fea6a5   8 months ago   13.3kB
hello-world   latest    feb5d9fea6a5   8 months ago   13.3kB

IMAGE_ID是一样的,说明两个是同一个镜像。

查找镜像

拉取镜像前,一般都要先搜寻镜像,找到合适的镜像拉取下来

# option为可选命令,keyword为要搜寻的内容
docker search [option] keyword

可选命令:

  • -f,–filter filter :过滤输出内容;
stars:star数大于等于某个值,如:-f stars=10;

is-official:是否官方镜像,值为true或false;

is-automated:是否自动构建,值为true或false;
  • –format string:格式化输出内容;
  • –limit int:限制输出结果个数,默认为25个;
  • –no-trunc:不截断输出结果;
删除镜像
# IMAGE可以是镜像名或者镜像ID
docker rmi [OPTIONS] IMAGE [IMAGE...]
#或
docker image rm [OPTIONS] IMAGE [IMAGE...]

可选参数:

  • -f,–force:强制移除镜像;
  • –no-prune:不删除未标记的父类;
清理镜像

使用Docker一段时间后,系统可能遗留一些临时的镜像文件,以及一些没有使用的镜像。可以用prune命令清理

docker image prune

可选参数

  • -a,–all:删除所有无用镜像,不光是临时镜像;
  • -filter filter:过滤符合条件的镜像;
  • -f,-force:强制删除镜像,不进行提示确认;
创建镜像
  • 基于已有容器创建
  • 基于本地模板导入
  • 基于Dockerfile创建
# 在存放Dockerfile文件的目录执行,注意有个点
docker build [option] .

可选参数:

  • -t,–tag:指定镜像名称标签,例-t name:tag
  • -f,–file:Dockerfile 的名称(默认为 ‘PATH/Dockerfile’

容器

创建容器
docker [container] create NAME[:TAG]

例子:

docker create -it ubuntu:latest

create的容器是停止的,需要通过start启动它。

查看容器列表
# 显示正在运行的容器
docker ps

可选参数:

  • -a:显示所有容器,包括已停止的;
  • -q:只显示容器ID

例子:

# docker ps
CONTAINER ID   IMAGE           COMMAND   CREATED              STATUS         PORTS     NAMES
f228a84a9dc7   ubuntu:latest   "bash"    About a minute ago   Up 9 seconds             bold_wright
# docker ps -a
CONTAINER ID   IMAGE           COMMAND    CREATED         STATUS                     PORTS     NAMES
f228a84a9dc7   ubuntu:latest   "bash"     2 minutes ago   Up 56 seconds                        bold_wright
04f22456096c   hello-world     "/hello"   3 minutes ago   Exited (0) 3 minutes ago             hungry_ptolemy
# docker ps -aq
f228a84a9dc7
04f22456096c
启动容器
# 指定启动的容器ID
docker [container] start CONTAINER_ID
新建并启动容器
docker [container] run NAME[:TAG]

例子:

docker run hello-world

常用命令:

  • -d:是否在后台运行容器;
  • -i:保存标准输入打开;
  • -t:是否分配一个伪终端;
  • -v,–volume:挂载容器卷;
  • -e:指定容器内环境变量;
  • –expose:公开一个端口或一系列端口;
  • -h,–hostname:容器主机名;
  • –rm:容器退出时自动移除;
  • -w,–workdir:容器内的工作目录
停止容器
# 指定容器ID
docker stop CONTAINER_ID
删除容器
# 指定容器ID
docker rm CONTAINER_ID
# 批量删除容器
docker rm $(docker ps -q) 或 docker rm $(docker ps -aq)
进入容器
attach
docker attach CONTAINER_ID
  • 默认退出容器快捷键:ctrl + p ctrl + q;
  • ctrl + d 或者exit也可以退出容器,不过如果只有一个bash进程,容器会退出并停止运行;

当多个窗口同时attach到同一个容器内时,所有的窗口都会同步显示;当某个窗口因命令阻塞时,其他窗口也无法操作。

exec
docker exec [options] CONTAINER_ID

可选参数:

  • -d , --detach:在容器后台执行命令;
  • –detach-keys=“”:指定将容器切换回后台的按键;
  • -e, --evn=[ ]:指定环境变量列表;
  • -i:打开标准输入接受用户输入命令;
  • -t:分配伪终端;
  • -u ,–user=“”:执行命令的用户或ID

通过exec方式进入容器,ctrl + d 或者exit退出容器,容器并不会关闭。

退出容器
  • 默认退出容器快捷键:ctrl + p ctrl + q;
  • ctrl + d 或者exit也可以退出容器,不过如果只有一个bash进程,容器会退出并停止运行;
  • 通过exec方式进入容器,ctrl + d 或者exit退出容器,容器并不会关闭。

Dockerfile

Docker 可以通过读取 Dockerfile 中的指令来自动构建镜像。 Dockerfile 是一个文本文档,其中包含用户可以在命令行上调用以组装镜像的所有命令。使用 docker build 用户可以创建一个连续执行多个命令行指令的自动构建。

指令
FROM

Docker是按顺序执行指令的,一个Dockerfile必须是以FROM开头的。FROM指令定义要构建的镜像的基础镜像(父镜像)。

FROM [--platform=<platform>] <image> [AS <name>]
#或
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
#或
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

例子:

FROM centos:latest
MAINTAINER(deprecated)

MAINTAINER 指令设置生成镜像的作者字段。 LABEL 指令是一个更灵活的版本,应该使用它,因为它可以设置您需要的任何元数据,并且可以轻松查看,例如使用 docker inspect。

MAINTAINER [name]

例子:

MAINTAINER John <xxxxx@163.com>
LABEL

LABEL 指令将元数据添加到镜像。 LABEL 是键值对。要在 LABEL 值中包含空格,像在命令行解析中一样使用引号和反斜杠

LABEL <key>=<value> <key>=<value> <key>=<value> ...

例子:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

一个镜像可以有多个标签,也可以在一行里指定多个标签。

LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"
RUN

RUN 指令将在当前镜像之上的新层中执行任何命令并提交结果。生成的提交镜像将用Dockerfile 中的下一步。

# RUN有两种编写方式
#方式一:shell形式
RUN <command>
#方式二:exec形式
RUN ["executable", "param1", "param2"]

例子:

RUN echo 'hello world'

RUN ["/bin/bash", "-c", "echo hello world"]
CMD

一个 Dockerfile 中只能有一个 CMD 指令。如果有多个 CMD,则只有最后一个 CMD 才会生效。
CMD和RUN不同,CMD是在容器启动执行的命令,而RUN是在构建镜像时所要执行的命令。
CMD有三种编写格式:

# exec形式 推荐使用
CMD ["executable","param1","param2"]
# 作为 ENTRYPOINT 的默认参数
CMD ["param1","param2"]
# shell形式
CMD command param1 param2

例子:

CMD echo "this is a test."

CMD ["/bin/bash/wc", "--help"]
ENV

ENV 指令将环境变量 设置为值 。该值将在构建阶段的所有后续指令的环境中,也可以在许多中内联替换。该值将被解释为其他环境变量,因此如果没有转义引号字符将被删除。与命令行解析一样,引号和反斜杠可用于在值中包含空格

ENV <key>=<value> ...
#或 适用于单个环境变量
ENV <key> <value>

例子:

ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy

ENV允许在一个指令内写多个= …

ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
    MY_CAT=fluffy
ADD

ADD 指令从 复制新文件、目录或远程文件 URL,并将它们添加到路径 处的镜像文件系统。

# 两种编写方式, 包含空格的路径需要后一种形式
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]

例子:

# 相对路径 会将文件添加到<WORKDIR>/relativeDir/
ADD test.txt relativeDir/
# 绝对路径 添加到/absoluteDir/目录
ADD test.txt /absoluteDir/
  • 如果 是可识别压缩格式(identity、gzip、bzip2 或 xz)的本地 tar 存档,则将其解压缩为目录
  • 如果 不存在,它会连同其路径中所有缺失的目录一起创建。
COPY

COPY 指令从 复制新文件或目录,并将它们添加到路径 的容器文件系统中。可以指定多个 资源,但文件和目录的路径将被解释为相对于构建上下文的源。

# 两种编写方式, 包含空格的路径需要后一种形式
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]

例子:

# 添加到相对路径,<WORKDIR>/relativeDir/
COPY test.txt relativeDir/
# 添加到绝对路径
COPY test.txt /absoluteDir/
  • 如果 不存在,它会连同其路径中所有缺失的目录一起创建。
ENTRYPOINT

ENTRYPOINT 在每次镜像启动的时候都会执行的切入点,可以与CMD结合使用,CMD里面的命令作为ENTRYPOINT的参数,如果docker run传递参数,则CMD指令会被覆盖。

# 两种方式:首选exec方式
ENTRYPOINT ["executable", "param1", "param2"]
# shell方式
ENTRYPOINT command param1 param2
VOLUME

VOLUME 指令创建一个具有指定名称的挂载点,并将其标记为保存来自本机主机或其他容器的外部挂载卷。该值可以是 JSON 数组、VOLUME [“/var/log/”] 或具有多个参数的纯字符串,例如 VOLUME /var/log 或 VOLUME /var/log /var/db。

VOLUME ["/data"]

例子:

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
WORKDIR

WORKDIR 指令为 Dockerfile 中任何 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指令设置工作目录。如果 WORKDIR 不存在,即使它没有在任何后续 Dockerfile 指令中使用,它也会被创建。

WORKDIR /path/to/workdir

例子:

WORKDIR /a
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
EXPOSE

EXPOSE 指令通知 Docker 容器在运行时侦听指定的网络端口。可以指定端口监听 TCP 还是 UDP,如果不指定协议,则默认为 TCP。
EXPOSE 并不会直接将端口自动和宿主机某个端口建立映射关系。它充当构建映像的人和运行容器的人之间的一种文档类型,关于打算发布哪些端口。要在运行容器时实际发布端口,请使用 docker run 上的 -p 标志来发布和映射一个或多个端口,或者使用 -P 标志来发布所有暴露的端口并将它们映射到高阶端口。

EXPOSE <port> [<port>/<protocol>...]
完整示例

上传jar包,编写Dockerfile并构建镜像,并启动容器。

  1. 创建一个简单的springboot项目并编写一个测试API,创建一个test.txt文件
@RestController
public class Test {

    @Value("${server.port}")
    private String port;

    @GetMapping("hello")
    public String hello() {
        return "hello world:" + port;
    }

}
  1. 编写Dockerfile文件
# 基于jdk8构建镜像
FROM openjdk:8

# 镜像的信息
LABEL version="1.0" author="Fun" 

# 环境变量
ENV MY_NAME="fun"

# 工作目录
WORKDIR /mydocker

# run指令打印信息
RUN echo "my first docker image"

# 添加一个txt文件
ADD test.txt  docs/

# 添加jar包
COPY demo.jar  jar/

# 监听容器8081端口
EXPOSE 8081

# 创建挂在容器卷
VOLUME docs/

# 容器启动后 执行动作
CMD ["java", "-jar", "/mydocker/jar/demo.jar", "--server.port=8081"]
  1. 新建mydocker文件夹,并上传jar、txt、Dockerfile文件
[root@xxxx mydocker]# ls
demo.jar  DockerFile  test.txt
  1. 执行docker 镜像构建命令
# 别忘了后面这个点
docker build -t demo:1.0 .
  1. 镜像构建具体步骤
Sending build context to Docker daemon  17.61MB
Step 1/10 : FROM openjdk:8
8: Pulling from library/openjdk
e756f3fdd6a3: Pull complete 
bf168a674899: Pull complete 
e604223835cc: Pull complete 
6d5c91c4cd86: Pull complete 
5e20d165240e: Pull complete 
93f67470f837: Pull complete 
5ddf137867aa: Pull complete 
Digest: sha256:b802a84e81b7947baee122ca9a60431babf8a8ddb0f2ae9a7c848bcef0a1e2eb
Status: Downloaded newer image for openjdk:8
 ---> 5bf086edab5e
Step 2/10 : LABEL version="1.0" author="Fun"
 ---> Running in c9b1066715c7
Removing intermediate container c9b1066715c7
 ---> f449d35b8b9f
Step 3/10 : ENV MY_NAME="fun"
 ---> Running in 39b93ba99ffa
Removing intermediate container 39b93ba99ffa
 ---> 1fd49121922c
Step 4/10 : WORKDIR /mydocker
 ---> Running in 8c5286f43ab7
Removing intermediate container 8c5286f43ab7
 ---> 343d47c3a9f0
Step 5/10 : RUN echo "my first docker image"
 ---> Running in f17ab5e8958b
my first docker image
Removing intermediate container f17ab5e8958b
 ---> 4e32c784ac83
Step 6/10 : ADD test.txt  docs/
 ---> b1851243bb43
Step 7/10 : COPY demo.jar  jar/
 ---> 100f0dc15fc5
Step 8/10 : EXPOSE 8081
 ---> Running in e325d2625218
Removing intermediate container e325d2625218
 ---> 010f0b38b08d
Step 9/10 : VOLUME docs/
 ---> Running in 286d9408a9a6
Removing intermediate container 286d9408a9a6
 ---> 0a9e5c52085b
Step 10/10 : CMD ["java", "-jar", "/mydocker/jar/demo.jar", "--server.port=8081"]
 ---> Running in 8dbbfea2e8fd
Removing intermediate container 8dbbfea2e8fd
 ---> b335bd988224
Successfully built b335bd988224
Successfully tagged demo:1.0
  1. 查看镜像信息
[root@xxx mydocker]# docker image inspect demo:1.0
[
    {
        "Id": "sha256:b335bd988224eeefd9b3d2810ebcaf8e1b82c3322f789c75e4188a36fda82e58",
        "RepoTags": [
            "demo:1.0"
        ],
        "RepoDigests": [],
        "Parent": "sha256:0a9e5c52085b7c25a9cbe3168a57ab7f3f194f9d0a3aa0a18f123f586d762dcd",
        "Comment": "",
        "Created": "2022-06-17T06:35:33.883505299Z",
        "Container": "8dbbfea2e8fd07f5670b8607442a836026ba53454cb2bbcd3cda8a1cedf0326e",
        "ContainerConfig": {
            "Hostname": "8dbbfea2e8fd",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "8081/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/openjdk-8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "JAVA_HOME=/usr/local/openjdk-8",
                "LANG=C.UTF-8",
                "JAVA_VERSION=8u332",
                "MY_NAME=fun"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"java\" \"-jar\" \"/mydocker/jar/demo.jar\" \"--server.port=8081\"]"
            ],
            "Image": "sha256:0a9e5c52085b7c25a9cbe3168a57ab7f3f194f9d0a3aa0a18f123f586d762dcd",
            "Volumes": {
                "docs/": {}
            },
            "WorkingDir": "/mydocker",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "author": "Fun",
                "version": "1.0"
            }
        },
        "DockerVersion": "20.10.17",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "8081/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/openjdk-8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "JAVA_HOME=/usr/local/openjdk-8",
                "LANG=C.UTF-8",
                "JAVA_VERSION=8u332",
                "MY_NAME=fun"
            ],
            "Cmd": [
                "java",
                "-jar",
                "/mydocker/jar/demo.jar",
                "--server.port=8081"
            ],
            "Image": "sha256:0a9e5c52085b7c25a9cbe3168a57ab7f3f194f9d0a3aa0a18f123f586d762dcd",
            "Volumes": {
                "docs/": {}
            },
            "WorkingDir": "/mydocker",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "author": "Fun",
                "version": "1.0"
            }
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 543691246,
        "VirtualSize": 543691246,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/15e56de0bd814810995d4da86e218cb18935f6dadbb97a3affc9b2b4a3cf03be/diff:/var/lib/docker/overlay2/23eab21c422577e5ec896ff9dbd18e3063fd246d6fb681bb43be6b007336ce8b/diff:/var/lib/docker/overlay2/c9a43ad37461e50311809b93a63804af3af70101e04a72848f917134f463864c/diff:/var/lib/docker/overlay2/69dc4259f57056a214d2d2a0ccdadbdc3cb298f1d52c6154d4c646afa6871c7c/diff:/var/lib/docker/overlay2/d15f9622e491ea90520cf179f2bd2d64980fdcd30695f26cb6d574b1cf0e6001/diff:/var/lib/docker/overlay2/adc8cf192e0db1020647ff0a1fca3c60273843114cb17d04311eced41a6411b6/diff:/var/lib/docker/overlay2/fe0f47b1b87540484a8bba5a02952d8358c4f3f17014592d1ee1b856515b6df5/diff:/var/lib/docker/overlay2/d7ae4375b68144465db8ac292e7d9c498fe0c06eeb0b6f641e65dbe3d9e45869/diff:/var/lib/docker/overlay2/69344787dff656b087417b23c169fc28577d0dfbc05b8831ab0f263136d35424/diff",
                "MergedDir": "/var/lib/docker/overlay2/43b63877fe8eca172f46c22f379e2728f813415d22f9be50664a570195efa756/merged",
                "UpperDir": "/var/lib/docker/overlay2/43b63877fe8eca172f46c22f379e2728f813415d22f9be50664a570195efa756/diff",
                "WorkDir": "/var/lib/docker/overlay2/43b63877fe8eca172f46c22f379e2728f813415d22f9be50664a570195efa756/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:e7597c345c2eb11bce09b055d7c167c526077d7c65f69a7f3c6150ffe3f557ea",
                "sha256:7dbadf2b9bd82a7447533776d0c8de6687cfcf241d3aa993ed8a86ad1347c6e0",
                "sha256:9177197c67d08b25357b0b5ba8f7b944f321970dddbbe93b36cb726e9bdfd678",
                "sha256:ee509ed6e976cdad5adda963902f78e442ea5fc05f955bd2c2c9026789f84b42",
                "sha256:817e710a8d04f5308a96c771a268c572dcaf2bd225ee2b9944e4ecfbbf05b9a9",
                "sha256:075d20daa2c3cc076c0258bb4f7598c692c0d8e22b3159d3168da95b18153ea5",
                "sha256:1cc35fbb41f87f182ab998b4d8709af972ee8221d2cb3c56e72f16599fa22e93",
                "sha256:92c103032574517b2af85aa2c41ec91ad7484c75b7ed85cf401d3086097246cc",
                "sha256:cb4e321d114d6e6a91bc8235cbf0e40f9b782ba76beae3a2665fe6c4d2f0027e",
                "sha256:da69f444f0e5cb03cb14b4675ae9e87982ef35048e38fdacbf9965e3e6f811fe"
            ]
        },
        "Metadata": {
            "LastTagTime": "2022-06-17T14:35:33.909683871+08:00"
        }
    }
]
  1. 启动容器
docker run -it -p 8081:8081 demo:1.0
[root@xxx ~]# netstat -nptl | grep 8081
tcp      0   0 0.0.0.0:8081      0.0.0.0:*   LISTEN   27752/docker-proxy  
tcp6     0   0 :::8081           :::*        LISTEN   27756/docker-proxy
  • 可以看到宿主机开启了8081端口
  1. 请求测试接口http://宿主机IP:8081/hello
hello world:8081

常见问题

1. 容器卷挂载方式
  • docker run -v 宿主机目录 : 容器目录
  • 在Dockerfile 编写VOLUME指令
2. 具名挂载和匿名挂载

具名挂载

  • 绝对路径挂载
# 宿主机目录前有 /
docker run -v  /宿主机目录 : /容器目录
  • 相对路径挂载
# 宿主机目录少了 /
docker run -v  宿主机目录 : /容器目录

匿名挂载

  • docker run 方式且不指定宿主机目录
docker run -v 容器目录
  • Dockerfile方式
VOLUME 目录
或
VOLUME ["目录1","目录2"]

具名挂载和匿名挂载的区别
以demo:1.0 镜像为例

docker run -d -p 8081:8081 \
       -v demo-vol:/mydocker/demo-vlo-1 \ 
       -v /mydocker/demo-vol:/mydocker/demo-vol-2 \
       -v /mydocker/demo-vol-3  demo:1.0

查看容器详细信息,Mounts配置项

docker inspect 容器id
"Mounts": [
    # 在Dockerfile配置的 VOLUME docs/,在宿主机的/var/lib/docker/volumes/目录下
    {
    "Type": "volume",
    "Name": "e99aa4cb8b970c090f79742912c87895adaf30d10962a6231d9b6539d47be22b",
    "Source": "/var/lib/docker/volumes/e99aa4cb8b970c090f79742912c87895adaf30d10962a6231d9b6539d47be22b/_data",
    "Destination": "docs",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
    },
    # 相对路径下的容器卷,也在/var/lib/docker/volumes目录下,不过名称是我们自定义的
    {
    "Type": "volume",
    "Name": "demo-vol",
    "Source": "/var/lib/docker/volumes/demo-vol/_data",
    "Destination": "/mydocker/demo-vlo-1",
    "Driver": "local",
    "Mode": "z",
    "RW": true,
    "Propagation": ""
    },
    # 绝对路径下的容器卷,在我们指定的目录/mydocker/demo-vol
    {
    "Type": "bind",
    "Source": "/mydocker/demo-vol",
    "Destination": "/mydocker/demo-vol-2",
    "Mode": "",
    "RW": true,
    "Propagation": "rprivate"
    },
    # 不指定宿主机目录的容器卷,也在/var/lib/docker/volumes目录下
    {
    "Type": "volume",
    "Name": "4ab7e344c46367bebcad8ce4d5168e9ccb9c7539ed4724ad9e984d549cf1fa80",
    "Source": "/var/lib/docker/volumes/4ab7e344c46367bebcad8ce4d5168e9ccb9c7539ed4724ad9e984d549cf1fa80/_data",
    "Destination": "/mydocker/demo-vol-3",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
    }
],

总结:

  • 匿名挂载容器卷目录会被分配到/var/lib/dovker/volumes/下;
  • 具名挂载绝对路径才是真正的指定宿主机目录,相对路径还是在var/lib/dovker/volumes/下,只不过目录名称是我们指定的;
3. docker run -v 和Dockerfile中VOLUME的区别
  • Dockerfile挂载容器卷是匿名的,docker run -v 可以匿名也可以具名挂载;
  • docker run -v 可以指定宿主机目录;