Docker学习笔记

1、Docker简介

 Docker核心是隔离。各个项目之间独立运行,不会交叉感染。

将项目和环境打包成镜像放到仓库。

容器化技术不是模拟一个完整的操作系统。

比较Docker和虚拟机技术的不同:
1、传统虚拟机,虚拟出—套硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件,docker有着比虚拟机更少的抽象层
2、容器内的应用直接运行在宿主机的内容,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了
3、每个容器间是互相隔离的,每个容器内都有一个属于自己的文件系统,互不影响。

Docker相当于一个轻量化的虚拟机。轻巧,高效。

DevOps(开发、运维)
应用更快速的交付和部署
传统:—堆帮助文档,安装程序
Docker:打包镜像发布测试,—键运行
更便捷的升级和扩缩容
使用了Docker之后,部署应用就和搭积木一样
项目打包为一个镜像,负载均衡,扩展服务器A、服务器B
更简单的系统运维
在容器化之后,开发,测试环境都是高度一致的。
更高效的计算资源利用
Docker是内核级别的虚拟化,可以在一个物理机上可以运行很多的容器实例

2、Docker安装

2.1、组成

镜像(image ) :
通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)。
容器(container ) :
Docker利用容器技术,独立运行一个或者一个组应用,通过镜像来创建的。
启动,停止,删除,基本命令!
目前就可以把这个容器理解为就是一个简易的linux系统
仓库(repository ) :
仓库就是存放镜像的地方!
仓库分为公有仓库和私有仓库!
Docker Hub(默认是国外的)
阿里云.....都有容器服务器(配置镜像加速!)
docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像==>run ==> tomcat01容器(提供服务器),

 

查看linux内核和系统的版本号:要求大于3.10

2.2、安装过程

直接去官网的文档中查看安装详细过程和命令操作

https://docs.docker.com/engine/install/ubuntu/

使用存储库安装

1、更新apt软件包索引并安装软件包以允许apt通过HTTPS使用存储库:

$ sudo apt-get update

$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

2、添加Docker的官方GPG密钥:

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

 验证密钥 :

$ sudo apt-key fingerprint 0EBFCD88

pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]

 

3、设置存储库:

$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

4、安装docker引擎和容器:

 $ sudo apt-get update
 $ sudo apt-get install docker-ce docker-ce-cli containerd.io

5、验证是否安装Docker Engine成功:

$ sudo docker run hello-world

 

2.3、卸载Docker

1、卸载Docker Engine,CLI和Containerd软件包:

$ sudo apt-get purge docker-ce docker-ce-cli containerd.io

2、删除镜像容器:

$ sudo rm -rf /var/lib/docker

2.4、阿里云镜像加速

登录阿里云成功后选择镜像加速器,运行以下命令即可:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://c9xycdhd.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

2.5、run的运行流程

3、Docker命令

 3.1、镜像命令

 1、docker images 显示主机上的镜像, -a显示所有镜像,-q只显示镜像ID

 

 

2、docker search mysql  从仓库搜索镜像

 

 

3、docker pull mysql 从仓库拉取镜像,就是下载

 

 默认是下载最新版的mysql,也可指定版本,如 docker pull mysql:5.7

 

 4、docker rmi 删除镜像

docker rmi -f 0d64f46acfd1  根据镜像的ID删除镜像

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

3.2、容器命令

1、docker run [OPTIONS] image 根据镜像新建并启动容器。image是镜像ID或镜像名称

 常见选项:

 -d: 后台运行容器,并返回容器ID

注意:后台启动后若无前台进程则自动停止 

-i: 以交互模式运行容器,通常与 -t 同时使用

 -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用

 -P: 随机端口映射,容器内部端口随机映射到主机的端口

 -p: 指定端口映射

 --name="nginx01": 为容器指定一个名称

 -h "heheda": 指定容器的hostname;

 -e username="wangyi": 设置环境变量;

 -m :设置容器使用内存最大值;

 2、docker ps 列出所有运行的容器,-a则包括历史容器

 

 

3、退出容器

exit:直接将容器停止并退出

ctrl + P + Q  容器不停止退出

 

4、删除容器

docker rm 容器id :删除容器,不能删除正在运行的容器,得加-f

docker rm -f $(docker ps -aq) :删除所有容器

 

5、启动和停止容器的操作

  docker start 容器id :启动容器

  docker restart 容器id :重启容器

  docker stop 容器id :停止容器

  docker kill 容器id :强制停止容器

 

6、docker commit :从容器创建一个新的镜像。

-a :提交的镜像作者;

-c :使用Dockerfile指令来创建镜像;

-m :提交时的说明文字; 

-p :在commit时,将容器暂停

运行tomcat,进入后cp webapps.dist 里面的内容到webapps,这个操作发生在容器的顶层可写层,然后打包成一个新的镜像:

 

3.3、其他常用命令

 1、查看日志

docker logs 选项 容器id

-f:跟踪日志输出

-t:显示时间戳

--tail N:显示最新的N条容器日志

--since="2020-02-02":显示某个开始时间的所有日志

 

 

 

 2、查看容器进程信息

docker top cid

 

 

 3、查看镜像的源数据

docker inspect 容器id

 

 

 4、进去当前正在运行的容器

docker exec -it  容器id bash :   进入容器后开启一个新的终端,可以在里面操作

 

 

 docker attach 容器id :进入容器正在执行的终端,不会启动新的进程。

5、拷贝容器文件到主机

docker cp Cid:文件目录 主机目录 

 

 

 

 

3.4、 部署练习

1、部署Nginx

docker search Nginx    搜索nginx

docker pull Nginx         下载nginx镜像

docker run -d --name nginx01 -p 3000:80 nginx    启动容器,配置主机-容器间的端口映射

 

 

 在阿里云的安全组中开放3000端口,访问:服务器:3000

 

 

 

 

2、部署Tomcat

docker pull tomcat      下载镜像

docker run -d --name tomcat01 -p 3001:8080 tomcat     运行容器

docker exec -it tomcat01 /bin/bash    进入容器

 

 发现webapps里面是空的,这是因为阿里云下载的是最小的镜像,保证最小可运行环境,剔除了其他的东西。这时外网去访问的话就啥都看不到,把webapps.dist里面的数据拷贝到webapps中就可以看见猫了。

 

 

3  部署MySQL

拉取mysql5.7后运行,添加配置文件和数据挂载,在环境里配置密码:

 

启动容器后,在本机用Navicat连接数据库成功:

 

 

新建一个test01数据库,就会发现宿主机的data里也会新增一个test01目录:

 

4、Docker镜像详解

1、Docker镜像是什么?

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

 /var/lib/docker/image/overlay2:存储镜像管理数据的目录,以使用的存储驱动命名,在我的ubuntu系统上,使用的驱动为overlay2。

 

2、关于镜像目录

 

 

 

repositories.json中记录了和本地image相关的repository信息,主要是name和image id的对应关系,当
image从registry上被pull下来后,就会更新该文件。

 

在imagedb/content/sha256里,都是各个镜像的配置文件:

 

 文件名称就是文件内容的sha256码,它的前12位对应的是docker images中的IMAGE ID:

 

 

 查看其中的nginx镜像配置文件:

 

 拉到最下方:

 

在bootfs之上的rootfs层,可以看到这个nginx的image包含了5个layer,从上到下依次是从最底层到最高层。

这个用命令docker image inspect nginx也可以看到。

 

镜像层的元数据都保存在layerdb中:

 

 

 

3、注意点

注意:

1、docker镜像其实类似于一个操作系统的发行版,而操作系统由内核空间bootfs和用户空间rootfs(根文件系统)组成。镜像使用的是宿主机的内核,而rootfs用户空间就是各种layers层的堆叠。

2、Docker 在 Linux 上支持很多存储引擎(Snapshotter),如AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,每个存储引擎都有自己的镜像分层、镜像层共享以及写时复制(CoW)技术的具体实现。

3、镜像的各镜像层都是只读的(read-only layer),而容器层是一个可写层。在容器中添加数据或者修改现有数据的所有读写操作都会存储在此可写层中。删除容器后,可写层也会被删除,而基础镜像则保持不变。

4、统一文件系统(union file system)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。我们可以在图片的右边看到这个视角的形式。

5、docker run是docker create和docker start两个命令的组合。

6、容器需要读取某个文件时,直接从底部只读层去读即可,而如果需要修改某文件,则将该文件拷贝到顶部读写层进行修改,只读层保持不变。每个容器都有自己的读写层,因此多个容器可以使用同一个镜像,另外容器被删除时,其对应的读写层也会被删除

7、Dockerfile 是软件的原材料,Docker 镜像是软件的交付品,而 Docker 容器则可以认为是软件的运行态。从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。

 

问题:

1、到底是docker引擎本身依赖于操作系统内核还是docker镜像依赖于操作系统内核?怎么理解docker镜像跨平台这句话?

 

5、docker容器数据卷

5.1、挂载宿主机文件或目录到容器数据卷

可以直接挂载宿主机文件或目录到容器里,可以理解为目录映射,这样就可以让所有的容器共享宿主机数据,从而只需要改变宿主机的数据源就能够影响到所有的容器数据。

ctrl +p q 退出容器

docker inspect 容器id:查看挂载情况

在宿主机修改目录里的数据会一一映射到容器里的目录。

挂载文件:

 

 

 

 

 

将容器stop后修改宿主机目录数据,再次start容器,数据依然同步。

将容器删除,宿主机上的数据依旧存在。

 

5.2、 具名挂载和匿名挂载

-v 名称:容器目录     ——》具名挂载

-v 容器目录               ——》匿名挂载

-v 宿主机目录:容器目录  ———》指定目录挂载

具名挂载启动nginx:

查看挂载,发现匿名的和具名的区别:

 

 

那么这些目录挂载到宿主机上面的哪里呢?

通过inspect查看挂载目录:

 

 

 

只读:

 

 这里的 :ro 表示只读read-only,只能在宿主机操作,容器内操作不了。 

5.3、 数据卷容器

多个容器之间也可实现数据共享

启动nginx08,创建数据卷:

 

 启动nginx09,通过 --volumes-from 挂载到nginx08:

 

 进入nginx09发现volume01已经存在了:

 

这样两个容器的volume01目录就可以共享数据了。一方删除目录不影响另一方。

在容器内是不能删除的:

 

6、DockerFile

自定义构件镜像。

6.1、 dockerfile 命令

1、主要组成部分

    dockerfile执行build命令时,是从上倒下依次执行的,dockerfile的基本组成部分如下。

        主要部分                              代表性命令
        基础镜像信息                      FROM
        维护者信息                          MAINTAINER
        镜像操作指令                      RUN、COPY、ADD、EXPOSE、WORKDIR、ONBUILD、USER、VOLUME、ENV等
        容器启动时执行指令           CMD、ENTRYPOINT

2、各命令详解

FROM:指定基础镜像,必须为dockerfile中的第一个命令

复制代码
格式:
  FROM <image>
  FROM <image>:<tag>
  FROM <image>@<digest>
示例:
  FROM mysql:5.6
注:
  tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
复制代码

 

MAINTAINER: 维护者信息

格式:
    MAINTAINER <name>
示例:
    MAINTAINER Jack
    MAINTAINER jack@163.com
    MAINTAINER Jack <jack@163.com>

 

 RUN:构建镜像时执行的命令,一个文件中可以包含多个RUN命令

复制代码
RUN用于在镜像容器中执行命令,有以下两种命令执行方式:
shell执行,即/bin/sh 
格式:
    RUN <command>
exec执行 格式: RUN ["executable", "param1", "param2"] 要注意的是,executable是命令,后面的param是参数 示例: RUN yum install -y nginx RUN ["yum", "install", "-y", "nginx"] 注:   RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache
复制代码

        由于RUN命令会生成一个镜像层,所以RUN并不是越多越好,需要合理使用,如果一个RUN中执行多个命令,可以使用 && 连接,如果命令过长,可以使用 \ 换行,例如

复制代码
RUN apt-get update && apt-get install -y \  
 bzr \
 cvs \
 git \
 mercurial \
 subversion

并且这样写还有个优点,apt-get update 和 apt-get install 被放在一个 RUN 指令中执行,这样能够保证每次安装的是最新的包。如果 apt-get install 在单独的 RUN 中执行,则会使用 apt-get update 创建的镜像层,而这一层可能是很久以前缓存的
复制代码

 

ADD:将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget

如果目的位置不存在,Docker会自动创建所需要的目录结

复制代码
格式:
    ADD <src>... <dest>
    ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
    ADD hom* /mydir/          # 添加所有以"hom"开头的文件
    ADD hom?.txt /mydir/      # ? 替代一个单字符,例如:"home.txt"
    ADD test relativeDir/     # 添加 "test" 到 `WORKDIR`/relativeDir/
    ADD test /absoluteDir/    # 添加 "test" 到 /absoluteDir/
  注意:

      需要复制的本地文件一定要放在Dockerfile文件的同级目录下
  原因:

      因为构建环境将会先上传到Docker守护进程,而复制是在Docker守护进程中进行的。任何位于构建环境之外的东西都是不可用的。ADD指令的目的的位置则必须是容器内部的一个绝对路径。
复制代码

 

COPY:功能类似ADD,但是是不会自动解压文件,也不能访问网络资源

        就是不能解压,其他限制条件跟ADD一样

 

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参数覆盖构建时所设置的工作目录。
复制代码

 

LABEL:用于为镜像添加元数据

格式:
    LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
  LABEL version="1.0" description="这是一测试工程"
注:
  使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。

 

ENV:设置环境变量

复制代码
格式:
    ENV <key> <value>  #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
    ENV <key>=<value> ...  #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
示例:
    ENV myName John Doe
    ENV myDog Rex The Dog
    ENV myCat=fluffy
复制代码

 

EXPOSE:指定暴露镜像的端口供主机做映射

复制代码
格式:
    EXPOSE <port> [<port>...]
示例:
    EXPOSE 80 443
    EXPOSE 8080
    EXPOSE 11211/tcp 11211/udp
注:
  EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
复制代码

 

VOLUME:添加卷,用于指定持久化目录

复制代码
格式:
    VOLUME ["/path/to/dir"]
示例:
    VOLUME ["/data"]
    VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
注:
  一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1 卷可以容器间共享和重用
2 容器并不一定要和其它容器共享卷
3 修改卷后会立即生效
4 对卷的修改不会对镜像产生影响
5 卷会一直存在,直到没有任何容器在使用它
复制代码

 

USER:指定运行容器时的用户名或 UID,后续的操作都会使用指定用户。使用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参数来覆盖所指定的用户。
复制代码

 

ARG:用于指定传递给构建运行时的变量

格式:
    ARG <name>[=<default value>]
示例:
    ARG site
    ARG build_user=www

 

ONBUILD:用于设置镜像触发器

复制代码
格式:
  ONBUILD [INSTRUCTION]
示例:
  ONBUILD ADD . /app/src
  ONBUILD RUN /usr/local/bin/python-build --dir /app/src
注:
  当所构建的镜像被用做其它镜像的基础镜像时(比如用户的镜像需要从某为准备好的位置添加源代码,或者用户需要执行特定于构建镜像的环境的构建脚本),该镜像中的触发器将会被钥触发

 

例如创建镜像image-A
  FROM ubuntu
  ...
  ONBUILD ADD . /var/www
  ...


然后创建镜像image-B,指定image-A为基础镜像,如
  FROM image-A
  ...

 

然后在构建image-B的时候,日志上显示如下:
  Step 0 : FROM image-A
  # Execting 1 build triggers
  Step onbuild-0 : ADD . /var/www
  ...

复制代码

 

CMD:构建容器后调用,也就是在容器启动时才进行调用,存在多个CMD时只有最后一个生效,也支持exec语法。

复制代码
格式:
    CMD ["executable","param1","param2"] (执行可执行文件,优先)
    CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
    CMD command param1 param2 (执行shell内部命令)
示例:
    CMD echo "This is a test." | wc -
    CMD ["/usr/bin/wc","--help"]
注:
   CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
复制代码

 

ENTRYPOINT:配置容器,使其可执行化。配合CMD可省去"application",只使用参数。

复制代码
格式:
    ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
    ENTRYPOINT command param1 param2 (shell内部命令)
示例:
    FROM ubuntu
    ENTRYPOINT ["top", "-b"]
    CMD ["-c"]
注:
   ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
复制代码

注意!!!! CMD和ENTRYPOINT的区别

    CMD和ENTRYPOINT同样作为容器启动时执行的命令,区别有以下几点:
          CMD的命令会被 docker run 的命令覆盖而ENTRYPOINT不会
          如使用CMD ["/bin/bash"]或ENTRYPOINT ["/bin/bash"]后,再使用docker run -ti image启动容器,它会自动进入容器内部的交互终端,如同使用docker run -ti image /bin/bash。
          但是如果启动镜像的命令为docker run -ti image /bin/ps,使用CMD后面的命令就会被覆盖转而执行bin/ps命令,而ENTRYPOINT的则不会,而是会把docker run 后面的命令当做ENTRYPOINT执行命令的参数。

     放个例子

复制代码
Dockerfile中为
ENTRYPOINT ["/user/sbin/nginx"]

然后通过启动build之后的容器
docker run -ti image -g "daemon off"

此时-g "daemon off"会被当成参数传递给ENTRYPOINT,最终的命令变成了
/user/sbin/nginx -g "daemon off"

如果Dockerfile中定义的是CMD,则会被覆盖
复制代码

CMD和ENTRYPOINT都存在时,CMD的指令就变成了ENTRYPOINT的参数,并且此CMD提供的参数也会被 docker run 后面的命令覆盖

复制代码
Dockerfile中指令
..
ENTRYPOINT ["echo","hello","i am"]
CMD ["docker"]

之后启动构建之后的容器

使用docker run -ti image
输出“hello i am docker”

使用docker run -ti image world
输出“hello i am world”
复制代码

 

最后说一下docker build命令,Dockerfile写完后要生产镜像,就需要docker build

docker build 命令用于使用 Dockerfile 创建镜像,语法

docker build [OPTIONS] PATH | URL |-

参数说明:

  • --build-arg=[] :设置镜像创建时的变量;

  • --cpu-shares :设置 cpu 使用权重;

  • --cpu-period :限制 CPU CFS周期;

  • --cpu-quota :限制 CPU CFS配额;

  • --cpuset-cpus :指定使用的CPU id;

  • --cpuset-mems :指定使用的内存 id;

  • --disable-content-trust :忽略校验,默认开启;

  • -f :指定要使用的Dockerfile路径;

  • --force-rm :设置镜像过程中删除中间容器;

  • --isolation :使用容器隔离技术;

  • --label=[] :设置镜像使用的元数据;

  • -m :设置内存最大值;

  • --memory-swap :设置Swap的最大值为内存+swap,"-1"表示不限swap;

  • --no-cache :创建镜像的过程不使用缓存;

  • --pull :尝试去更新镜像的新版本;

  • --quiet, -q :安静模式,成功后只输出镜像 ID;

  • --rm :设置镜像成功后删除中间容器;

  • --shm-size :设置/dev/shm的大小,默认值是64M;

  • --ulimit :Ulimit配置。

  • --tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。

  • --network: 默认 default。在构建期间设置RUN指令的网络模式

示例

复制代码
使用当前目录的 Dockerfile 创建镜像,标签为 runoob/ubuntu:v1。
docker build -t runoob/ubuntu:v1 . 

使用URL github.com/creack/docker-firefox 的 Dockerfile 创建镜像。
docker build github.com/creack/docker-firefox

也可以通过 -f Dockerfile 文件的位置:
$ docker build -f /path/to/a/Dockerfile .

在 Docker 守护进程执行 Dockerfile 中的指令前,首先会对 Dockerfile 进行语法检查,有语法错误时会返回:
$ docker build -t test/myapp .
Sending build context to Docker daemon 2.048 kB
Error response from daemon: Unknown instruction: RUNCMD
复制代码

6.2、 构建Tomcat镜像

 

1、准备tomcat的压缩包,在 https://mirrors.cnnic.cn/apache/tomcat 这个网站选一个版本

wget https://mirrors.cnnic.cn/apache/tomcat/tomcat-9/v9.0.36/bin/apache-tomcat-9.0.36.tar.gz

 

2、准备jdk8的压缩包:(同意协议,不然无法解压)

wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.tar.gz

 

3、 编写Dockerfile文件

 

 

后台启动容器会导致不正常退出:

 

 

前台启动容器会导致:

 

 如果通过run 后面加 /bin/bash会成功启动,但是这样会覆盖掉Dockerfile中的CMD命令,导致容器启动后无法自动启动tomcat服务:

 

 这时需手动启动tomcat服务:通过unset CATALINA_HOME 解决掉配置文件读取问题

那么怎么才能正常启动容器后自动启动tomcat同时又解决环境配置问题呢?

最终的Dockerfile:

 

 

通过tail -f循环使得CMD命令得以持续:

 

顺便输出日志,或者啥也不做: tail -f /dev/null

补充:-f和-F的区别

tail -f     等同于--follow=descriptor,根据文件描述符进行追踪,当文件改名或被删除,追踪停止

tail -F    等同于--follow=name  --retry,根据文件名进行追踪,并保持重试,即该文件被删除或改名后,如果再次创建相同的文件名,会继续追踪

 

 成功启动tomcat。

 

 

拓展:

在Docker中,进程管理的基础是Linux内核的PID命名空间技术。在不同的PID命名空间下,可以有相同的PID。Linux内核为所有的PID命名空间维护了一个树状的数据结构,最顶层是系统初始化时创建的root namespace(根命名空间), 父节点可以看到子节点中的进程,并可以通过信号等方式对子节点中的进程产生影响。反过来,子节点不能看到父节点名空间中的任何内容,也不可能通过kill或ptrace影响父节点或其他名空间中的进程。在docker中有一个很特殊的进程——PID为1的进程,这也是docker的主进程,通过Dockerfile中的 ENTRYPOINT 和/或 CMD指令指定。当主进程退出的时候,容器所拥有的PID命名空间就会被销毁,容器的生命周期也会结束。

在docker中,对于CMD和 ENTRYPOINT,支持两种进程执行方式:exec和shell。

shell的格式是:

CMD "executable param1 param2"

最终PID1进程将是: /bin/sh  ,而 ”executable param1 param2”是他的一个子进程。/bin/sh执行完毕后,主进程退出,容器也会自动退出。

Exec的格式是:

CMD ["executable","param1","param2"]

最终的PID1进程是: executable param1 param2

参考:https://zhuanlan.zhihu.com/p/30555962

7、docker-compose

前面我们使用 Docker 的时候,定义 Dockerfile 文件,然后使用 docker build、docker run 等命令操作容器。然而微服务架构的应用系统一般包含若干个微服务,每个微服务一般都会部署多个实例,如果每个微服务都要手动启停,那么效率之低,维护量之大可想而知。

使用 Docker Compose 可以轻松、高效的管理容器,它是一个用于定义和运行多容器 Docker 的应用程序工具

Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。

Docker-Compose将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(container)。Docker-Compose运行目录下的所有文件(docker-compose.yml,extends文件或环境变量文件等)组成一个工程,若无特殊指定工程名即为当前目录名。一个工程当中可包含多个服务,每个服务中定义了容器运行的镜像,参数,依赖。一个服务当中可包括多个容器实例,Docker-Compose并没有解决负载均衡的问题,因此需要借助其它工具实现服务发现及负载均衡。

Docker-Compose的工程配置文件默认为docker-compose.yml,可通过环境变量COMPOSE_FILE或-f参数自定义配置文件,其定义了多个有依赖关系的服务及每个服务运行的容器。

安装使用见官方文档:https://docs.docker.com/compose/gettingstarted/

posted @ 2020-08-29 11:21  天青色wy  阅读(304)  评论(0编辑  收藏  举报