• Docker快速指南


    Docker使用Go语言开发,基于Linux内核的cgroup、namespace以及AUFS等技术对进程进行封装隔离,是一种操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。

    Docker则使用宿主机内核提供的隔离机制创建沙盒环境,容器内的应用进程直接运行于宿主的内核。 因为容器内没有虚拟硬件和内核,容器在启动时间、执行效率、内存占用以及镜像大小等方面相对于传统虚拟机都拥有很大优势。

    Docker容器将程序及其运行环境打包在一起,镜像创建后可以在任何安装了Docker的系统上运行,无需配置运行环境, 加之较小的镜像体积极大方便了协作开发和部署。

    使用Dockerfile将镜像构建过程透明化,也便于开发和运维人员理解程序的运行环境。

    Docker相对于虚拟机的优势来源于它运行与宿主内核而减少了开销,这使得Docker不能虚拟不同的内核环境。也就是说我们可以很容易地在Windows操作系统上启动一个Linux虚拟机,但是在Windows上启动一个基于Linux的Docker容器则是很困难的事情。

    docker官方已经发布了docker for macdocker for windows。目前docker for mac使用MAC OS内核提供的HyperKit虚拟化技术代替了docker-toolbox采用的使用Linux虚拟机提供支持的方式。

    目录:

    What's Docker

    cgroup和namespace是Linux内核提供的两种隔离机制,是Docker虚拟化的技术基础:

    • cgroup: 全名Control Groups, Linux内核提供的用于监控和管理进程组占用资源的机制。 这里的资源包括CPU,内存和IO等硬件资源。
    • namespace: 为某个进程提供独立的空间,包括独立的:
      • 进程树: 进程拥有独立的init进程及其下进程树
      • 文件系统: 进程拥有独立的根目录/及其下目录树
      • 用户: 进程可以定义自己的用户,组和权限系统
      • 协议栈: 进程可以拥有独立的ip地址及tcp/udp端口空间
      • 其它

    在了解隔离机制之后我们可以了解Docker中的两个核心概念:

    • 容器:容器的本质是进程,它拥有独立的命名空间。因此容器表现很像一个虚拟操作系统,拥有自己的进程树,文件系统等。
    • 镜像:镜像是容器运行依赖的文件系统,就像每个Linux操作系统时都需要挂载root文件系统/,镜像就是容器的root文件系统。

    Docker采用服务端/客户端架构:

    • 守护进程(dockerd): Docker服务端每个dockerd下可以运行多个容器,此外还提供了镜像和容器管理的功能。
    • 客户端: 通过API与dockerd通信进行操作,官方提供了命令行客户端以及Go和Python语言的SDK
    • 宿主机:用于运行dockerd及其容器的操作系统环境
    • Registry:Docker镜像存储中心,用于管理和共享docker镜像。官方存储中心DockerHub中提供了大量官方和第三方镜像。

    Docker采用UnionFS技术将镜像设计为分层结构,即一个镜像分为多层,每一层在上一层的基础上构建(即存储增量)。在容器中只能看到所有层叠加后的结果,隐藏了分层的结构。因为镜像层会被其它层依赖,为了保证下层能正常工作, 镜像层在创建后就无法进行修改。

    Get Started

    Docker目前分为免费的社区版(CE)和付费的商业版(EE)两种, 这里我们选用社区版。 Docker官网上提供了各种常用操作系统的安装说明:

    下面看一个简单的示例:

    finley@mbp:$ uname
    Darwin
    finley@mbp:$ docker run -it ubuntu
    root@528ab91753d6:/# uname
    Linux
    

    在执行docker run命令后发现我们已经从宿主机Mac的终端进入到了Linux终端中。 这个运行中的"Linux"就是容器,启动这个虚拟的Linux环境所需的文件即是镜像。

    上面的示例中我们使用docker代替了ubuntu虚拟机,对比之下docker在镜像大小,启动时间和运行内存占用方面都具有巨大的优势。 

    因为启动docker容器的开销和启动相应进程的开销基本相同, 因此完全可以使用docker代替原生进程, 避免复杂的编译安装配置过程。

    $ docker run -p 6379:6379 -d redis
    3a5748eef653
    $ redis-cli
    127.0.0.1:6379> keys *
    (empty list or set)
    

    这个示例中我们一键安装并启动了redis-server。

    在终端中输入docker命令则会显示所有命令和使用帮助, 在docker命令后添加--help选项可以查看该命令的帮助信息, 如docker run --help可以查看run命令的帮助。

    镜像

    本节将简单介绍如何搜索和管理镜像, 为介绍容器做准备。更多关于镜像的构建和共享的内容将在下文中介绍。

    docker images

    docker images命令用于显示本地所有镜像:

    REPOSITORY TAG IMAGE ID CREATED SIZE
    ubuntu latest 00fd29ccc6f1 3 weeks ago 111MB
    redis latest 1e70071f4af4 4 weeks ago 107MB

    和其它软件一样docker镜像也可以演进出不同版本,tag用于标识镜像的版本。

    repository代表同一镜像多个版本的集合, 它的值是一个URI用于全局唯一标识一组镜像,如"registry.cn-hangzhou.aliyuncs.com/acs/agent"。

    对于DockerHub中的镜像则会省略仓库的地址,诸如dorowu/ubuntu-desktop-lxde-vncubuntu就是DockerHub中的镜像。

    由此可见,repositorytag可以唯一标识docker镜像。

    除此之外每个镜像还拥有一个摘要(DIGEST),docker images --digest可以显示镜像的摘要。

    DockerHub是docker官方提供的公有仓库,docker search命令用于根据关键字搜索DockerHub中的镜像:

    format: docker search TERM
    demo: docker search ubuntu
    
    NAME DESCRIPTION STARS OFFICIAL AUTOMATED
    ubuntu Ubuntu is a ... 7076 [OK]
    dorowu/ubuntu-desktop-lxde-vnc Ubuntu with openssh-server and NoVNC 156 [OK]

    docker pull

    docker pull命令用于从远程下载镜像,可以通过NAME:TAGNAME@DIGEST的格式来指明目标镜像。

    当只提供了镜像NAME时,默认下载tag为latest的镜像。

    $docker pull ubuntu
    $docker pull ubuntu:16.04
    $docker pull ubuntu@sha256:fbaf303d18563e57a3c1a0005356ad102509b60884f3aa89ef9a90c0ea5d1212
    

    NAME也可以是私有仓库中一个REPOSITORY的URI。

    docker rmi

    docker rmi用于删除镜像,可以使用IMAGE IDREPOSITORY:TAG来标记一个容器。

    容器

    docker run

    docker run命令用于新建一个容器并启动, 是最重要的和最常用的docker命令之一。

    format: docker run IMAGE CMD ARGS
    

    docker run命令的标准执行流程包括:

    • 检查本地是否包含指定的镜像,若不存在就从公有仓库下载
    • 在只读的基础镜像层上挂载一个可读写层,创建容器的文件系统
    • 根据文件系统启动容器
    • 将容器与宿主机桥接
    • 用指定的身份登录容器,并在指定目录下执行CMD ARGS参数指定的命令
    • 在命令执行完成后关闭容器

    docker容器在命令执行完毕后会自动退出, 容器的生存周期仅决定于执行命令所需的时间。 如果在容器中执行bash等长期运行的命令, 就可以保证容器长期运行。

    docker run命令默认会把标准输出流(stdout)重定向到终端,并与容器保持连接状态(attach)。

    在attach状态下, 容器退出之前doceker run命令不会返回,而是在终端回显容器的输出。 若发出kill信号(如ctrl + c快捷键)杀死docekr run, 那么容器也会提前退出。

    容器对文件系统的修改在可读写层,不会对镜像产生影响, 除非使用docker commit创建新的镜像层。 容器退出后其文件系统仍将保存在磁盘中,下次启动后会保留所有修改。

    打开终端

    docker run命令默认将容器的标准输出流重定向到终端, 但是没有将终端的标准输入流(stdin)重定向到容器。 也就是说,容器无法接收我们在终端中输入的命令。

    使用-i--interactive选项会保持容器的输入流(stdin)打开,即使docker run不与容器保持attach状态。

    docker run -i ubuntu bash命令可以打开一个ubuntu终端, 该终端也可以接受我们输入的指令。

    和标准的Linux系统一样,docker镜像也为用户指定了默认终端。 使用-t--tty选项会打开一个虚拟终端(Pseudo-TTY)。

    也就是说,docker run -it ubuntu命令可以轻松地打开一个可交互ubuntu虚拟环境。

    后台运行

    docker run命令默认与容器保持连接状态(attach), -d--detach选项可以与容器断开连接。 docker run命令在显示容器ID后立即返回,容器则会在后台运行。

    上文redis-server的示例即使用了-d选项, docker run立即返回, redis-server在后台继续运行。

    $ docker run -p 6379:6379 -d redis
    3a5748eef653
    $ redis-cli
    127.0.0.1:6379>
    

    端口映射

    如上文中redis-server示例, 我们经常使用docker容器提供服务,因此需要docker容器监听宿主机的某个端口。

    docker run -p 6379:6379 -d redis将对宿主机TCP6379端口的访问映射到容器的TCP6379端口。

    -p 6379:6379/udp则可以映射udp访问(虽然对redis-server来说没有意义)。 多个-p选项可以映射多个端口docker run -p 80:8080 -p 8080:8081 -d my_server.

    端口映射是将对宿主机某个端口的访问映射到容器的某个端口上, 容器访问宿主机端口不需要配置端口映射。


    挂载数据卷

    -v选项可以将宿主机上某个目录挂载到容器中的某个目录

    $ ls ~/myvol
    history.txt
    $ docker run -it -v ~/myvol:/app ubuntu
    root@e690c508219e:/# ls /app
    history.txt
    

    上述指令将宿主机目录~/myvol挂载到镜像的/app目录下,/app目录下原来的内容会被隐藏而是显示宿主机目录~/myvol下的内容。

    这种方式我们称为在容器上挂载了数据卷,对数据卷的读写独立于容器之外:

    • 容器对数据卷的修改将立即存储到数据卷所在的(即宿主机的文件系统)上
    • 除非指明删除数据卷,否则容器删除不会对数据卷产生影响
    • 其它进程对数据卷的修改将立即生效

    若数据卷~/myvol或挂载点/app不存在的时候, docker会自动创建空目录。

    docker提供了独立于容器的数据卷管理功能,参考docker volume

    为容器命名

    每个容器都拥有一个唯一的CONTAINER ID来标识,但ID不便于记忆和使用。 因此在docker run创建容器时可以使用--name选项来为容器指定一个名称。

    在某个dockerd中容器名称是唯一的, 我们可以使用容器名来唯一指定容器。

    示例:docker run --name my_ubuntu -it ubuntu

    退出时自动删除

    docker run --rm选项会在容器退出时自动删除容器。 使用该命令时需谨慎, 容器一旦删除便不可恢复。

    自定义工作目录

    docker run -w PATH选项会在启动容器时,使用PATH参数指定的路径作为工作目录。

    docker create

    docker create命令与docker run指令极为相似,区别在于docker run创建容器后自动启动容器, 而docker create不自动启动容器需要使用docker start命令来启动。

    docker ps

    docker ps命令用于显示容器的信息,默认情况下显示运行中的容器:

    finley@mbp $ docker ps
    
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    3a5748eef653 redis "docker-entrypoint..." 3 hours ago Up 3 hours 0.0.0.0:6379->6379/tcp redis-server
    c10921921bfb ubuntu "/bin/bash" 3 hours ago Up 52 seconds my_ubuntu

    -a选项可以显示包括已停止容器在内的所有容器信息。

    docker start

    docker start命令用于启动一个已停止的容器,默认情况下不与容器连接(attach)也不将输入重定向到容器。

    $ docker run --name redis-server -p 6379:6379 redis
    $ docker stop redis-server # 此时已经存在一个名为redis-server的已停止容器
    $ docker start redis-server
    redis-server
    $ redis-cli
    127.0.0.1:6379>
    

    若使用-a--attach选项将docker start与容器连接(attach), 终端将回显容器输出。

    -i--interactive选项则会将输入重定向到容器。

    $ docker run --name my_ubuntu -it ubuntu
    root@c10921921bfb # exit
    # 此时已经存在一个名为my_ubuntu的已停止容器
    $ docker start -ai my_ubuntu
    root@c10921921bfb:/#
    

    docker exec

    docker exec用于让一个正在运行的容器执行命令,命令执行完成后docker exec将返回容器继续运行。

    $ docker run --name my_ubuntu -d ubuntu
    $ docker exec my_ubuntu ls
    home bin ...
    

    默认情况下docker exec与容器连接,-d--detach选项可以不与容器连接而在后台执行命令。

    docker run命令类似, -i选项用于将标准输入重定向到容器以便接收用户输入, -t选项可以打开终端。

    $docker exec -it my_ubuntu bash
    root@c10921921bfb:/# 
    

    docker attach

    docker attach命令用于与容器连接, 即将容器输出流重定向到终端,终端输入流重定向到容器。

    $ docker attach my_ubuntu
    # 再按一次回车
    root@c10921921bfb:/#
    

    当容器没有输出时终端中没有回显,可能令用户误以为卡死。 attach之后再次输入回车, bash将回显命令行提示符。

    attach状态下ctrl + c快捷键会发送SIGKILL信号中止容器, 而ctrl + p, ctrl + q快捷键会退出attach容器继续运行。

    docker stop

    docker stop用于终止容器的运行

    $docker stop redis-server
    

    docker stop命令会先发送SIGTERM信号要求容器中的进程执行退出操作,若达到超时时间(默认10s)容器仍未退出则会发送SIGKILL信号强制退出。

    -t-time选项可以秒为单位设置强制杀死之前的等待时间:

    $docker stop -t 20 redis-server
    

    docker kill

    docker kill命令将直接向容器发送SIGKILL命令停止容器:

    $docker kill redis-server
    

    -s--signal选项可以向容器发送指定的信号:

    docker kill -s SIGINT my_ubuntu
    

    docker cp

    docker cp命令负责在运行的容器和宿主机之间复制文件:

    # format: docker cp FROM TO 
    $ docker cp test.txt my_ubuntu:/root/test.txt
    $ docker cp my_ubuntu:/root/test.txt test.txt 
    

    docker rm

    docker rm用于删除一个镜像,通过镜像ID或镜像名来指定要删除的镜像, 默认情况下只能删除已退出的镜像:

    $ docker stop my_ubuntu
    $ docker rm my_ubuntu
    

    -f--force选项可以强制删除运行中的镜像。

    -v--volumes选项将删除所有挂载的数据卷。

    docker volume

    docker volume系列指令用于独立的管理数据卷, 请先阅读docker run:挂载数据卷

    create

    将宿主机上一个目录创建为数据卷:

    # format: docker volume create PATH
    $ docker volume create myvol
    

    ls

    查看所有数据卷:

    docker volume ls
    DRIVER  VOLUME NAME
    local   0c28b79a9b3f
    local   myvol
    

    inspect

    查看某个数据卷的详细信息:

    docker volume inspect myvol
    [
        {
            "CreatedAt": "2018-01-16T09:04:16Z",
            "Driver": "local",
            "Labels": null,
            "Mountpoint": "/var/lib/docker/volumes/myvol/_data",
            "Name": "myvol",
            "Options": {},
            "Scope": "local"
        }
    ]
    

    rm

    删除某个数据卷:

    docker volume remove myvol
    myvol
    

    prune

    删除所有未被使用的数据卷:

    docker volume prune
    WARNING! This will remove all volumes not used by at least one container.
    Are you sure you want to continue? [y/N] y
    Total reclaimed space: 0B
    

    使用数据卷

    docker rundocker create命令可以使用-v--volume选项来使用数据卷:

    docker run -d -it -v myvol:/app ubuntu
    

    docker会优先寻找数据卷列表中的myvol而不是当前目录下的myvol子目录。

    若找不到myvol数据卷且当前目录下也不存在myvol子目录,docker会自动创建myvol数据卷不会再当前目录下创建子目录。

    --mount选项虽然语法复杂,但是可以配置更多选项:

    docker run -it --mount source=my_volume,target=/app ubuntu
    

    构建镜像

    上文中已经介绍了如何获取和使用已有镜像,接下来介绍如何构建自己的镜像。

    我们可以将自己的程序及其运行环境打包成Docker容器,部署到服务器或者共享给其它开发者免去配置环境的烦恼。

    docker diff

    前文已经提到过Docker镜像采用分层结构,容器运行时无法修改镜像的内容,而是在镜像层上挂载了一个可读写层。

    docker diff命令可以查看容器对镜像的修改:

    $ docker run --name my_ubuntu -it ubuntu 
    # if exists: docker start -ai my_ubuntu
    root@c10921921bfb:~# echo "Hello, from finley" > hello.txt
    root@c10921921bfb:~# exit
    ➜  ~ docker diff my_ubuntu
    C /root
    A /root/.bash_history
    A /root/hello.txt
    

    我们打开一个ubuntu容器在/root目录中创建了hello.txt文件, 并在其中写入"Hello, from finley"。

    通过docker diff可以看出这个操作产生了三个影响:

    • 工作目录修改为/root, C代表变更工作目录
    • 命令历史.bash_history文件改变, A代表文件或目录内容发生改变
    • 修改了文件hello.txt

    docker commit

    docker commit命令根据容器对镜像的修改创建新的镜像层

    # format: docker commit CONTAINER REPOSITORY[:TAG]
    $docker commit my_ubuntu my_ubuntu:2018_01_14
    sha256:8096f47d8d6b80e52e617030938c7a83a9d50bafd73915d6952675e7126bb38a
    $docker images
    
    REPOSITORY TAG IMAGE ID CREATED SIZE
    my_ubuntu 2018_01_14 8096f47d8d6b Less than a second ago 111MB

    -a--author选项可以指定容器的作者, -m--message可以添加备注信息:

    $docker commit 
        -a "finley<finley@finley.pw>"  
        -m "say hello" 
        my_ubuntu my_ubuntu:2018_01_14
    

    -c--change选项可以添加一系列Dockerfile指令,关于Dockerfile的内容我们将在下文介绍。

    docker tag

    docker tag命令用于为镜像创建一个别名。

    # format: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
    $ docker tag ubuntu my_ubuntu
    

    TARGET_IMAGE可以是私有仓库REPOSITORY的URI,tag命令经常被用来协助将镜像推送到私有仓库。

    docker history

    docker history命令用于显示镜像各层的信息,即查看commit历史:

    $ docker history ubuntu
    

    Dockerfile

    docker commit命令虽然可以很方便的创建新的镜像,但是我们在容器内操作(特别是尝试性的操作)可能会在新镜像内产生无关的内容,如命令历史和日志等。

    Dockerfile是控制镜像构建过程的脚本,使用Dockerfile可以有效避免镜像中包含无关内容。

    Dockerfile中包含多行指令,每个指令会在镜像中创建一层。

    FROM nginx
    RUN echo '<h1>Hello from finley!</h1>' > /usr/share/nginx/html/index.html
    
    $ docker build -t nginx_hello .
    Step 1/2 : FROM nginx
      ---> 3f8a4339aadd
    Step 2/2 : RUN echo '<h1>Hello from finley!</h1>' > /usr/share/nginx/html/index.html
      ---> Running in 2b3c5df09f9c
      ---> a918263d0f2f
    Removing intermediate container 2b3c5df09f9c
    Successfully built a918263d0f2f
    Successfully tagged nginx_hello:latest
    $ docker run --name nginx_hello -p 80:80 -d --rm nginx_hello
    $ curl localhost
    <h1>Hello from finley!</h1>
    

    上面示例中我们以nginx为基础构建了一个新镜像,并启动它提供服务。

    在具体介绍Dockerfile的指令之前,我们先介绍一下docker build命令。

    docker build指令用于根据Dockerfile构建镜像,通常该指令需要一个PATH参数来指定某个目录做为构建上下文(context)。

    -f--file选项用于在构建上下文指定Dockerfile文件的路径, 默认为PATH/Dockerfile

    -t--tag选项用于为镜像指定标签,默认情况下名称仍然与基础镜像相同, 而-t NAME:TAG则会指定容器的名称。

    除了使用一个目录作为构建上下文之外,也可以使用tar压缩包、git仓库作为上下文, 甚至从标准输入中读取Dockerfile或tar进行构建。

    接下来介绍常用的Dockerfile命令:

    FROM

    FROM指令用于指定构建容器的基础镜像,标记镜像的语法与docker pull命令相同。

    除了使用已存在的镜像作为基础镜像之外还有一个特殊的镜像scratch, 它是一个空镜像。

    我们可以把静态编译的可执行文件放入空白镜像中,由内核直接执行可以极大的降低镜像的体积。

    RUN

    RUN命令在镜像中创建一个容器并执行指定指令,执行结束后commit修改作为镜像的一层。

    上文示例中的Step2展示了RUN指令运行的过程:

    • 创建一个中间容器(intermediate container): 2b3c5df09f9c
    • 运行命令echo '<h1>Hello from finley!</h1>' > /usr/share/nginx/html/index.html
    • 将修改提交,产生新的容器: a918263d0f2f
    • 删除中间容器:2b3c5df09f9c

    RUN命令有两种参数格式:

    • 命令行式: RUN ls -al
    • 函数调用式: RUN ["ls", "-al"]

    在实际执行过程中命令行式指令会被映射为RUN ["sh", "-c", "ls", "-al"]

    因为每个RUN指令都会生成一层镜像, 因此最好用&&将多条指令连接而不是写多条RUN指令。

    COPY

    COPY from to指令将文件或目录从构建上下文(context)将文件复制到镜像内部。

    COPY ./config.json /root/config.json
    

    WORKDIR

    WORKDIR path命令用于指定容器的默认工作目录。

    WORKDIR命令对Dockerfile中的后续命令都有影响, 除非有另一条WORKDIR命令修改了工作目录

    上文已经介绍过每条RUN指令都会创建一个临时容器, 因此RUN cd PATH &&...只对同一条RUN中的后续指令有效。

    USER

    USER命令用于指定容器中的当前用户:

    RUN groupadd -r redis && useradd -r -g redis redis
    USER redis
    RUN redis-server
    

    WORKDIR命令一样,USER指令直到下一条USER指令之前始终有效。

    CMD

    CMD命令用于指定启动容器的指令, 和RUN命令一样有两种格式。

    EXPOSE

    EXPOSE命令用于声明需要暴露哪些接口,注意EXPOSE命令没有建立端口映射, 需要在创建容器时启动端口映射。

    ENV

    ENV命令用于为容器设置环境变量:

    ENV DEBUG=on VERSION='1.0' 
    

    ENTRYPOINT

    ENTRYPOINT指令和CMD一样,用于指定启动容器的指令。 当指定了ENTRYPOINT之后,CMD命令的内容将被作为参数传递给ENTRYPOINT指定的指令。

    首先创建一个容器:

    FROM ubuntu
    CMD ls
    
    $ docker build -t ls:v1 .
    $ docker run --rm ls:v1
    bin boot dev etc home lib ...
    

    如果我们试图传递-al选项给ls以显示更详细的信息:

    $ docker docker run --rm ls -al
    container_linux.go:265: starting container process caused "exec: "-al": executable file not found in $PATH"
    

    根据docker run的语法我们试图让ls镜像执行-al命令代替默认命令, 这当然行不通。

    用ENTRYPOINT代替CMD:

    FROM ubuntu
    ENTRYPOINT ["ls"]
    

    重新创建:

    $ docker build -t ls:v2 .
    $ docker run --rm ls:v2 -al
    total 72
    drwxr-xr-x   1 root root 4096 Jan 14 13:29 .
    drwxr-xr-x   1 root root 4096 Jan 14 13:29 ..
    -rwxr-xr-x   1 root root    0 Jan 14 13:29 .dockerenv
    drwxr-xr-x   2 root root 4096 Dec  1 21:53 bin
    drwxr-xr-x   2 root root 4096 Apr 12  2016 boot
    drwxr-xr-x   5 root root  340 Jan 14 13:29 dev
    

    ENTRYPOINT通常用于在执行容器CMD做一些准备工作, 比如官方redis镜像中:

    FROM alpine:3.4
    ...
    RUN addgroup -S redis && adduser -S -G redis redis
    ...
    ENTRYPOINT ["docker-entrypoint.sh"]
    

    docker run --entrypoint CMD可以用来更改容器的ENTRYPOINT。

    共享镜像

    现在我们已经了解如何构造自己的镜像,接下来的问题是如何将镜像分享给其它开发者或者部署到服务器。

    docker export

    docker export命令用于导出容器的快照, 默认输出到标准输出流,需要将输出重定向到文件进行保存。

    # format: docker export CONTAINER > TAR
    $ docker export my_ubuntu > my_ubuntu.tar
    

    或者使用-o--output选项

    $ docker export -o my_ubuntu.tar my_ubuntu
    

    docker export命令导出时会新建一个空白镜像然后将容器文件系统的内容写入,不包含容器基础镜像各层和tag等信息。

    docker save

    docker save用于将镜像存储为tar压缩包,默认导出到标准输出流需要重定向以写入文件

    # format: docker save IMAGE > TAR
    $ docker save ubuntu > ubuntu.tar
    

    或者使用-o--output选项

    $ docker save -o ubuntu.tar ubuntu
    

    docker save命令会将镜像各层及其tag信息导出到文件。

    docker import

    docker import命令用于导入tar格式的快照,生成的镜像只有一层不导入各层和tag信息。

    $ docker import my_ubuntu.tar my_ubuntu:v2
    

    该指令与docker export相对用于导入容器镜像,但也可以导入docker save生成的tar文件。

    docker load

    docker load用于导入tar格式的镜像副本,导入时保留各层和tag等元数据, 因此不需要指定镜像名和tag。

    默认从标准输入流导入:

    $ cat ubuntu.tar | docker load
    

    或者使用-i--input选项:

    docker load -i ubuntu.tar
    

    docker load命令与docker save命令相对,因为缺少元数据不能导入docker export生成的tar文件。

    Registry

    虽然docker支持以文件的形式导入导出镜像,但这种方式对于共享镜像来说仍十分不便。

    Docker官方提供了一个registry镜像,我们可以使用它轻松搭建私有仓库。

    $ mkdir registry
    $ docker run -d 
        -p 5000:5000 
        -v registry:/var/lib/registry 
        registry
    

    -v选项将./registry目录挂载到了容器中,这个目录将用来实际存储镜像。

    docker默认采用HTTPS方式推送和拉取镜像,本文不再介绍如何为私有仓库配置HTTPS证书。

    私有仓库可以配置权限认证,仅授权用户才能推送或拉取镜像,这里也不再详细介绍权限认证相关功能。

    docker push

    docker push命令用于将镜像推送到仓库,推送到的仓库由镜像的REPOSITORY属性决定。

    $ docker tag ubuntu 127.0.0.1:5000/finley/my_ubuntu:v1
    $ docker docker push 127.0.0.1:5000/finley/my_ubuntu:v1
    The push refers to a repository [127.0.0.1:5000/finley/my_ubuntu]
    f17fc24fb8d0: Mounted from registry/my_ubuntu
    6458f770d435: Mounted from registry/my_ubuntu
    5a876f8f1a3d: Mounted from registry/my_ubuntu
    d2f8c05d353b: Mounted from registry/my_ubuntu
    48e0baf45d4d: Mounted from registry/my_ubuntu
    v1: digest: sha256:f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663 size: 1357
    $ curl 127.0.0.1:5000/v2/_catalog
    {"repositories":["registry/my_ubuntu"]}
    

    首先,使用docker tag命令给想要推送的镜像unbuntu:latest创建一个别名127.0.0.1:5000/registry/my_ubuntu:v1

    在这个URI中, 127.0.0.1:5000是Registry的地址,finley是私有仓库中的一个命名空间, my_ubuntu是私有仓库中的一个REPOSITORY。

    访问127.0.0.1:5000/v2/_catalog来查看私有仓库中的镜像。

  • 相关阅读:
    AT5147[AGC036D]Negative Cycle【dp,模型转换】
    pjudge#21652[PR #4]到底有没有九【数位dp】
    legion:使用多工具分门别类地扫描多个目标,有用
    antix
    skipfish: web scaner, usefully
    dmitry
    maltego
    常见靶场
    reconng从多个源头搜集主机和域名,但需要apikey。不大好用
    account/username&password tool
  • 原文地址:https://www.cnblogs.com/Finley/p/8297939.html
Copyright © 2020-2023  润新知