拉取并使用docker的ubuntu镜像构建一个 交互式 的容器。

sudo docker run --name containerName -i -t ubuntu /bin/bash

参数解释:

``–name`是对于容器的命名

-i保证容器的STDIN开启,保证持续的标准输入;

-t为docker为容器分配一个tty终端

ubuntu提供的是镜像名,先从本机查找之后,若无则去dockerHub上查找

/bin/bash告知容器需要运行的命令

1.2 关闭容器与查看 Link to heading

在容器内键入exit可以退出容器,之后在宿主机上可以通过使用

docker ps -a

来查看所拥有的全部容器。

1.3 启动并附着到容器 Link to heading

当知道容器的名字或者uuid的时候可以使用

sudo docker start containerName
sudo docker start UUID

来重新运行容器,重新运行的容器会沿用docker run时候的命令,此时我们可以使用

sudo docker attach containerName

重新进入容器的会话。

1.4 使用非交互的守护式容器 Link to heading

有时候需要长期运行的容器,并不需要交互式会话,这时候我们会选择使用守护式容器(daemonized container)

sudo docker run --name containerName -d ubuntu /bin/sh

参数解释:

-d将容器放在后台运行

1.5 查看守护式容器信息 Link to heading

对于在后台运行的守护式容器,我们可以获取容器的日志。

sudo docker logs -f containerName

参数解释:

-f跟踪式运行

在运行容器的时候可以选用不同的日志驱动,常见的有

  • json-file(默认)
  • syslog:禁用docker log命令,并将所有日志输出都重定向到syslog。
  • none:禁用一切日志
  • 另外也可以通过使用docker top name来查看到容器内的进程,可以使用docker stats name来查看容器内部的硬件统计信息

    1.6 在守护式容器内部运行新的进程 Link to heading

    在docker1.3之后可以使用docker exec命令在容器内部额外启动新的进程

    sudo docker exec -d containerName command 
    

    参数解释:

    -d表示在后台运行

    command是需要的命令

    或者使用如下命令来启动前端的程序

    sudo docker exec -i -t containerName command
      1.7 守护式容器的关闭与重启
        Link to heading
    

    对于后台运行的守护式容器,可以使用docker stop containerName发送SIGTERM信号进行停止。

    而对于快速停止则可以使用docker kill命令发送SIGKILL信号。

    容器有可能因为某种错误而停止,可以通过在run的时候进行标记,来使其自动重启。

    sudo docker run --name containerName --restrat=always -i -t ubuntu /bin/bash
    

    这个属性具有两种标价,可以使用always来设置为自动重启,也可以使用on-failure:n中的n来指定最多重启次数。

    1.8 删除容器 Link to heading

    当容器已经不在使用的时候,可以通过rm命令

    sudo docker rm -f containerName
    

    参数解释:

    使用f可以无需关闭容器强行删除,不然则需要在删除容器前先关闭当前的容器。

    删除所有容器需要多个命令的组合,如下:

    sudo docker rm `sudo docker ps -a -q`
    

    在ps命令中,可以使用-a获得所有的容器,而-q的标志使得这条命令只返回id表

    二、Docker的镜像与容器 Link to heading 2.1 基本概念介绍 Link to heading

      Docker镜像是由文件系统叠加而成,最底端是一个引导文件系统(bootfs)。接下来第二层是root文件系统(rootfs),这可以是一种或者多种操作系统。接下来docker会使用联合加载(union mount)的技术在root文件系统层上加载更多的只读系统,将各层文件系统叠加到一起。

      这样的文件系统就是docker的镜像,最底下是一个基础镜像,而最上面会叠加一个读写文件系统,我们的程序会在这上面运行。使用的机制是写时复制,当修改一个文件的时候,会从底层复制这个读写层,在对其修改后隐藏下面的层。

    2.2 管理镜像 Link to heading

    可以使用sudo docker images来列出当前所拥有的全部镜像,也可以使用

    sudo docker images imageName
    

    来查看本地同一个镜像名,不同版本(tag)的镜像。

      镜像可以从仓库下载,默认的仓库会保存在Docker公司的Registry服务(Docker hub)下。每一个仓库都可以存放很多镜像,如Ubuntu仓库中会保存很多版本的镜像。

      Docker Hub中有两种类型的仓库,分别是用户仓库(user repository)和顶层仓库(top-level repository)

    用户仓库:userName/repositoryName

    顶层仓库:Name

    对于镜像文件,可以在使用run之前使用docker拉取相应的镜像文件

    sudo docker pull image:tag
    

    tag是image的版本,都在image的仓库之中。

    2.3 查找镜像 Link to heading

    我们可以通过使用search命令查找,所有可用的公共镜像。

    sudo docker search imageName
    

    这个命令会在docker上查找所有包含这个名字的镜像,我们可以拉去这些镜像并用其创建容器。

    2.4 构建镜像 Link to heading

      我们修改、更新和、管理镜像提供了两种方法。

  • 使用docker commit命令(不推荐)
  • 使用docker build命令和dockerfile文件
  • 在使用commit命令的时候,我们先启动容器,做自己需要的更改退出容器,之后可运行

    sudo docker commit -m "informations"  -a "author" id repositoryName/imageName:tag
    

    参数解释:

    id:容器的标识符

    -m:指定新创建的镜像的提交信息

    -a:作者的信息

    repositoryName:选择的镜像仓库名称,通常为自己的用户名

    imageName:镜像名

    tag:标签名

    注:这个命令提交的只是创建容器的镜像和容器当前状态的差别部分,使得更新十分轻量

    2.5 基于Dockerfile来构建镜像 Link to heading

      使用基于DSL语法的dockerfile可以构建镜像,具有更高的重复性、透明性、幂等性。

    2.5.1 快速尝试 Link to heading

    首先可以创建如下的基础Dockerfile

    # Version:0.0.1
    From ubuntu
    LABEL shenvinci maintainer="[email protected]"
    RUN apt-get update && apt-get install -y nginx
    EXPOSE 80
    

    参数解释:

    FROM指定了所用的基础镜像

    LABLE可以告知镜像的作者以及邮箱

    EXPOSE可以指定应用程序使用容器的端口

    在使用Dockfile构建镜像的时候,每一条指令都会创建一个新的镜像并提交,这样的操作逻辑即使在某一条失败而没有正常的结束,仍可以保留一个最后的镜像文件,可以用于调试。

      默认情况下RUN指令会使用命令包装器来执行,而对于不希望在Shell中运行的可以使用exec格式来运行指令,这种方式运行使用一个数组来指定要运行的命令和每一个参数。

    RUN ["apt-get","install","-y","nginx"]
    

    当有dockerfile存在后,我们可以使用build命令来构建镜像文件。

    docker build -t="repositoryName/imageName:tag" path
    

    参数解释:

    -t=用于表示镜像的仓库名,镜像名以及标签

    path表示dockerfile所处的路径,这个路径也可以是远端仓库的位置

    当使用构建的时候,dokerfile所处的上下文也会被传送到docker守护进程,如果有不想被传送的文件可以通过设置.dockerignore文件来选择需要过滤匹配的文件。

    2.5.2 Dockerfile的缓存逻辑 Link to heading

      因为在构建镜像的过程中,每一个步骤都会被构建为单独的镜像层,当再次使用dockerfile进行构建的时候,就会从最新一次有发生更改的部分继续进行构建。如果需要忽略所有缓存,则可以使用--no-cache命令来忽略所有缓存构建。

      因为这种特性,我们通常选择相似的docker模板,这样就可以不必重新运行前面的指令来构建镜像,而对于需要刷新的部分,我们可以在之前插入环境变量语句,如

    # Version:0.0.2
    From ubuntu
    LABEL shenvinci maintainer="[email protected]"
    ENV REFRESHED_AT 2021-9-30
    RUN apt-get update && apt-get install -y nginx
    EXPOSE 80
    

    ENV:设置了一个名为REFRESHED_AT的环境变量,指明了模板最新更新的时间,当更改时间后,后面的所有内容都会重新运行,使得包可以进行刷新。

    2.5.3 查看与使用新的镜像 Link to heading
    docker images repositoryName/imageName
    docker history repositoryName/imageName
    

    上面的第一个代码,可以查看自己构建的镜像的具体状况,而需要查看具体的构建全步骤过程,则可以使用下面的,查看到每一层的镜像文件以及相应的构建指令。

      当我们使用这种自己构建的镜像运行时候,我们的run命令需要加入新的内容

    sudo docker run -d -p 127.0.0.1:8080:80 --name containerName repositoryName/imageName command
    

    -p参数用于配置容器与宿主机的端口链接,如上述命令是把容器的80映射到宿主机127ip的8080端口上,当其中有参数被省略时,则会使用默认(随机)参数。当我们使用-P的时候,会将容器的80绑定到一个宿主机随机端口,然后将dockerfile中EXPOSE指定的端口全部公开.

    command命令是直接在容器内运行的内容,通常用于打开需要的服务

      我们可以使用docker ps -l命令查看所有容器被映射的端口,也可以使用docker port uuid 80查看这一容器80端口被映射到的宿主机端口位置。

    2.6 Dockerfile指令 Link to heading 2.6.1 CMD Link to heading

      CMD指令用于指定容器启动时运行的命令(而RUN指令的只是在被构建时候运行),通常的格式为

    CMD ["/bin/bash","-l"]
    

      Docker一直推荐使用数组来设置需要执行的命令。同时我们需要牢记docker run命令会覆盖CMD指令,同时要知道再Dockerfile中只能指定一条CMD指令,如果指定了多条则只有最后一条会被运行。

    2.6.2 ENTRYPOINT Link to heading

      这个指令与CMD十分类似,而最大的区别在于其不会被命令中的指令覆盖

    实际上所有的指令都会作为参数传入ENTRYPOINT中。

    在使用这个指令的时候我们也会使用数组进行内容的传输

    ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
    

    将这个命令,CMD命令以及docker run时选择的命令进行组合,可以得到默认参数的使用方法。

    ENTRYPOINT ["/usr/sbin/nginx"]
    CMD["-h"]
    
    docker run -t -i repositoryName/imageName -g  "daemon off;"
    

    在默认情况下,会使用CMD命令中的-h参数,但在run的时候如果添加了新的参数,则会对其进行覆盖,以此实现默认参数的效果。

    2.6.3 WORKDIR Link to heading

    这个指令可以在容器内部设置一个工作目录(切换内部的路径),用于CMDENTRYPOINT的执行。

    WORKDIR /opt/webapp
    CMD command
    

    我们为command指令设置了路径

    我们可以在run的时候通过-w来覆盖工作的目录。

    2.6.4 ENV Link to heading

    在镜像构建的过程中设置环境变量,这个环境变量可以在之后任何RUN指令中使用,就如同在命令前面指定了环境变量的前缀

    ENV RVM_PATH=/home/rvm TARGET_FIR=/opt/app
    RUN gem install unicorn
    WORKDIR $TARGET_FIR
    

    参数解释:

    设置了RVM_PATHTARGET_FIR两个环境变量,第一个可以为第二条RUN指令提供前缀条件,变成如RVM_PATH=/home/rvm RUN gem install unicorn而第二个则被用于提供了工作目录的位置。

    注意:在Dockerfile中设置的环境变量都是在容器中具有持久化作用的,而如果只是在使用docker run时候加入-e来传递的环境变量则只在运行的时候有效。

    2.6.5 USER Link to heading

    指定这个镜像以什么用户去运行,可以通过指定用户名(或uid)以及组(或gid)来选择。如果不选择默认会使用root

    USER user
    USER user:group
    USER uid
    USER uid:gid
      2.6.6 VOLUME
        Link to heading
    

    用来向基于镜像创建的容器添加卷(可以存在于一个或者多个容器内的特定的目录),卷可以绕过联合文件系统并提供共享以及持久化的数据功能,卷的功能可以让我们**把数据、数据库或者其他内容添加到镜像而不是将内容提交到镜像。**通常用来测试容器和内部的应用程序代码。管理日志,处理内部数据库。

    VOLUME ["/opt/project",/data]
    

    参数解释:

    为基于此镜像的任何容器创建了这两个挂载点。

    2.6.7 ADD Link to heading

    将构建环境下的文件和目录复制到镜像之中,需要指定源文件位置和目的文件位置两个参数。

    ADD contentPath aimPath
    

    参数解释:

    contentPath是上下文的文件,通过末尾的字符来判断是目录还是文件,如果以/结尾的就被认为是目录。

    在处理本地文件的时候,当归档文件被指定为源文件的时候,docker会把文件自动解开。(以URL指定目前不行)

    aimPath是镜像内的目标位置,如果目录不存在的话,会自动创建这样的新目录,其模式为文件模式为0755

    ADD指令会使得构建的缓存变得无效,当添加后,所有的后续指令都需要重新进行构建。

    2.6.8 COPY Link to heading

      与ADD命令基本类似,但不会做文件提取以及解压等方面的内容,需要注意,所有的文件源路径都必须是在Dockerfile的相对文件夹下,不能复制这个目录以外其他目录的内容。

    2.6.9 LABEL Link to heading

    这个指令可以为docker添加元数据,以键值对的形式展现出来。

    LABEL version="1.0" location="China" type="Web"
    

    推荐将所有的元数据都放入一条LABEL指令中,防止构建过多的镜像层。

    我们可以通过docker inspect repositoryName/imageName来查看容器内部的标签。

    2.6.10 STOPSIGNAL Link to heading

    用于设置停止容器的时候发送什么系统调用信号给容器,这信号必须是内核系统调用表中合法的数字(9)或者SIGNAME格式中信号名称(如SIGKILL)。

    2.6.11 ARG Link to heading

    用来定义可以在docker build命令运行的时候传递给构建运行的变量,在构建时候可以根据dockerfile中定义过的变量进行传递

    ARG build
    ARG webapp_user=user
    

    定义了两个变量,第二个给了一个默认值,接下来可以在使用docker build --build-arg build=1234这样的命令来添加参数

    2.6.12 ONBUILD Link to heading

    为当前的镜像添加触发器,当这个镜像被用作为其他镜像的基础镜像的时候,该镜像中的触发器会被执行。触发器会在下一个继承他的镜像的FORM之后添加这些被触发的指令

    ONBUILD ADD . /app/src
    ONBUILD RUN cd /app
    

    此处使用了两条命令,当有新的镜像Dockerfile继承当前的镜像时候,运行后回在FORM之后插入这两句话

    注意:触发器只能被子镜像继承,当孙镜像运行时候则不会再进行继承。

    2.7 删除自己的镜像 Link to heading

    当我们不再需要一个镜像的时候,我们可以使用

    sudo docker rmi repositoryName/imageName1 repositoryName/imageName2
    

    来删除这个镜像,这一行为同时也会删除构建这个镜像的时候所产生的每一层镜像,后面也可以不断往后罗列镜像,这将删除这镜像列表里面全部的镜像。

    2.8 Docker镜像的管理 Link to heading

    我们可以把自己在本地构建完成的镜像推送到远程仓库(默认为DockerHub),通过使用

    docker push repositoryName/imageName
    

    就可以将自己的镜像上传至自己的远程仓库之中。

      而除了这种方式,我们可以选择使用自动构建,这只需要将Github中含有Dockerfile文件的仓库链接到Docker Hub上,当我们向github推送时候,dockerhub也会自动更新(但这种方式就不可以使用docker push来发布镜像)。

    三、Docker实战操作 Link to heading 3.1 卷的挂载 Link to heading

    有些时候外面不想把应用或者代码构建到镜像之中

  • 同时对代码进行开发与测试
  • 代码改动十分频繁,不想在开发过程中重构镜像
  • 希望在多个容器之间共享代码
  • 这时候我们就需要使用docker的卷挂在来实现,通过在运行容器的时候使用-v 宿主机目录:容器内目录:读写权限来对本地与容器内的文件进行映射挂载。

    docker run -d -p 80 --name web -v ./web:/var/www/html/website:ro repositoryName/imageName2 cmd
      3.2 容器的链接
        Link to heading
      3.2.1Docker Networking
        Link to heading
    

    Docker Networking允许用户创建自己的网络,容器可以通过这个网络来互相通信,接下来是一些常用的管理指令。

    sudo docker network create name #创建一个桥接网络并命名为name
    sudo docker network inspect name #查看这个网络的信息
    sudo docker network ls # 查看当前系统中的所有网络
    sudo docker network rm # 删除一个网络
    

    当有网络后,我们在运行容器时候可以加上–net=name的标识符,把容器加入指定的网络之中。在网络内部启动的容器,docker会感知到所有在这个网络下的容器,并把这些信息都通过到当前容器的/etc/hosts文件把所有地址都保存到DNS之中。

    在网络之中的任何容器的地址,都可以通过hostname.app的形式被解析,当一个容器重启的时候,它们的IP地址也会被自动更新(即对容器底层的修改不会对程序的正常工作产生影响)

    3.2.2 Docker链接 Link to heading

      在使用run对容器进行运行的时候,我们增加--link containerName:linkName创建了客户联系,此时被运行的容器被称为客户容器,而另一个则是服务,我们为这个服务增加了linkName作为别名,这可以让我们一致的访问容器公开的信息,且无须关注底层容器的名字。

      将容器连接在一起可以让客户容器任意访问另一个容器,而不用对外公开端口。

    四、Docker编配和服务发现 Link to heading 4.1 Docker Compose Link to heading

      Dockers Compose通常被用于简单的Docker容器编配使用YAML文件定义一组需要启动的容器,以及容器运行时的属性,这些容器可以被称为是服务。我们可以很快的使用Compose来创建多容器应用栈。

    安装:使用pip install -U docker-compose可以进行最新版本的快速安装

      当应用的镜像构建完成之后,我们可以使用Compose来创建需要的服务,并定义启动时候需要的属性,这些属性都会被放置与YAML文件之中,样例:

    web:
        image : shenvinci/flask
        command : python app.py
        ports :
        - "5000:5000"
        volumes :
        - .:/composeapp
        links :
        - redis
    redis:
        image : redis 
    

    参数解释:

    开启了分别名为webredis的两个容器文件,并为其配置了相应的参数,Compose会使用这些参数生产多个容器并组成相应的容器栈。

    当切换至有YAML文件的目录下后,我们有一些常用的指令

    docker-compose up -d # 在后台运行容器栈
    docker-compose ps # 列出本地docker-compose.yml 文件中正在运行的所有服务
    docker-compose stop # 停止正在运行的所有服务
    docker-compose kill # 强制杀死正在运行中的服务
    docker-compose rm # 删除docker-compose服务