Dokcer入门及其Docker file的制作指令

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dokcer入门及其Docker file的制作指令相关的知识,希望对你有一定的参考价值。

Docker借鉴了kvm中应用镜像的方式,使得Docker的出现方便了容器的实现和使用,从此docker就占据了容器的市场。

docker:引擎:创建、运行容器,采用C/S架构
客户端:docker
服务端:dockerd,dockerd负责接收docker客户端的请求,客户端发送指令,dockerd通过镜像仓库,把镜像拖到本地,执行运行容器
容器是基于镜像启动的,如果本地没有镜像,dockerd会去远程拉取镜像。

IT行业的部署异构化程度越来越大。不同的开发平台,不同的运行平台,各个服务不同的需求环境。此时我们不必再根据不同的底层运行平台部署不同的运行环境。但是有了docker之后,只需保证能在docker上运行就可以,而不同的环境只要能运行docker就可以。
docker后来把lxc换成了libcontainer。
docker并没有解决容器之间的编排工具,google的kubernetes解决了这个问题。
容器提供的镜像包含了应用的所有依赖项,因而从开发到测试、生产环境中都有可移植性。
容器技术起源于FreeBSD jail,jail 的目的是让进程在经过修改的 chroot 环境中创建,而不会脱离和影响整个系统 — 在 chroot 环境中,对文件系统、网络和用户的访问都实现了虚拟化。尽管 Jail 在实施方面存在局限性,但最终人们找到了脱离这种隔离环境的方法。
镜像文件存储于Registry仓库中,镜像文件是分层构建的,所以其文件系统必需为分层文件系统(aufs,overlafs)
docker可以通过一个镜像文件启动多个容器,镜像是只读的,每一个容器都在镜像上层建立了一层内部可写的专用层,所有读写都仅在自己的专用层上实现。
Registry:一个镜像仓库服务器,可以通过一个套接字接受镜像的搜索和下载请求。镜像存储于Registry后面的存储空间中,可以有很多仓库,每一个仓库只放一种镜像,其中的每一个镜像都有其对应的tag(标签)。Registry对每一个仓库和镜像有一个索引,还有用户的账户密码,对仓库进行认证和管理。
每一个容器内可以允许多个进程、线程,但docker中每一个容器内部只运行一个进程及其子进程,只要次进程停止,则该容器也停止了。容器内进程运行的日志被送到控制台,这样查看日志的时候就不需要进入容器内部,只需在控制台查看。容器管理被简化。
Registry:通过一个httpd服务器提供服务,https为Registry,http为insecure Registyry
Registry可以自定义,也可以使用官方提供的

docker image

采用分层构建机制,最底层为bootfs,其之为rootfs
    bootfs:用于系统引导的文件系统,包括BootLoader和kernel,容器启动完成后会被卸载以节约内存资源;
    rootfs:位于bootfs之上,表现为docker容器的根文件系统;
        传统模式中,系统启动之时,内核挂载rootf时会首先将其挂载为只读,完整性自检完成后将其重新挂载为读写
        docker中,rootfs由内核挂载为只读模式,而后通过联合挂载技术额外挂载一个“可写”层。
位于下层的镜像称为父镜像,最底层的称为基础镜像
最上层为“可读写”层,其下的为“只读”层
automated builds:docker hub可以根据用户上传的指令制作docker镜像
webhooks:docker hub可以根据git服务器上代码的变化而自动制作镜像

制作镜像

制作镜像的时候只需要把最上面的可写层修改后保存。后续调用此镜像的时候,分层挂载系统会自动把基础镜像给挂载上去
运行为容器之后因为只有一个进程,所以就不可能通过systemd来管理各个进程了。

docker save  httpd:v0.1 centos7:v0.1 /data/centos-httpd.tar  通过docker save把本机的image保存至一个tar文件,通过scp等命令把tar文件传输到目标主机上
docker load -i centos-httpd.tar   根据tar文件解压镜像到本地

docker container commit -a "zhanghw" -c ‘CMD ["/bin/sh","-c","/bin/httpd -h var/www/html -f"]‘ -p b1 tiny-httpd:v5 
以正在运行的image为基础,用命令修改镜像启动后的首个进程。

docker 启动时显示:bridge-nf-iptables is disabled 解决方法

vim /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1 
让docker可以自动设定iptables  

docker network

三种内建虚拟网络:none,bridge,host
四种网络类型
closed container:没有外网接口,只要lo网卡
bridged container:一个lo网卡,一个桥接网卡
united container:网卡由两块网卡共用,共用同一个TCP/IP 协议栈
open container:直接使用host的物理网卡  

docker run --name a1 -it --network none httpd:2.4   
--network none        设置其网络为:closed container 
--network bridge        设置其网络为:bridged container
--network container:a1   设置其网络为:united container
--network host            设置其网络为:open container

docker -p 发布服务,暴露服务

把一个容器内的网络暴露到外部,让外部网络可以访问容器内的服务 
hostIP:hostPort --->  conIP:conPort   PNAT机制实现
在创建容器的时候使用-p选项指定
-p conPort  主机端口随机指派
-p conPort:hostPort  指定主机端口
-p hostIP::conPort  指定主机IP,::之间为主机端口,不指定为随机获取
-p hostIP:hostPort:conPort  指定主机的IP和端口
docker port continer 查看容器暴露端口的情况

docker network create

docker network create -d bridge --gateway 192.168.1.1 --subnet 192.168.1.0/24  vmnet1  
docker run --network     create container 通过--network指定多个网络时,只有最后一个生效
docker network connect bridge vmnet1  c1 把c1连接至vmnet1
docker network disconnect vmnet1 c1  剥离网络  
docker network rm vmnet1 删除网络  

docker inspect host 查看网络定义
docker network inpect -t 

create:根据指定信息创建网络
docker network create -h  查看帮助
docker network create -d bridge --gateway 192.168.1.1 --subnet 192.168.1.0/24 vmnet1
docker container run --name a1 --network vmnet1 -it --rm busybox:latest  启动容器时指定其网络
docker network connect bridge a1   吧container a1 连接到bridge网络上

Data volume

可写层依存于下一层镜像,docker commit 是根据最上层镜像的变化来创建镜像的,其底层的镜像通过联合挂载技术实现。
Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层。
写时复制(cow):如果一个文件需要修改,则会把在底层中的文件复制到最上面的可写层,联合挂载系统此时会屏蔽最下面只读层中的文件,只显示可写层中的文件。
大量业务数据不建议直接存储在容器镜像中:
    1.多层镜像读写性能差。
    2.容器一删除,其保存的文件也被删除
    3.磁盘的IO读写一直是服务器整体性能的瓶颈

卷:容器上的一个或多个目录,此类目录可绕过联合文件系统,与宿主机上的某个目录关联。独立于容器的生命周期实现数据持久化,实现数据和运行程序分离。
    ?Volume于容器初始化之时即会创建,由base image提供的卷中的数据会于此期间完成复制
    ? Data volumes can be shared and reused among containers
    ? Changes to a data volume are made directly
    ? Changes to a data volume will not be included when you update an image
    ? Data volumes persist even if the container itself is deleted
    ?Volume的初衷是独立于容器的生命周期实现数据持久化,因此删除容器之时既不会删除卷,也不会对哪怕未被引用的卷做垃圾回收操作

Docker支持两种类型的存储卷
    1.动态:container上指定存储卷,但至于对应的宿主机中的文件路径则是docker-daemon随机产生的,也称之为docker管理的卷。
    2.静态:container上指定、宿主机上对应的卷也由用户手动指定。

?为docker run命令使用-v选项即可使用Volume
? Docker-managed volume 
    ?  docker run -it -name bbox1 –v /data busybox 
    ?  docker inspect -f {{.Mounts}} bbox1 
        ? 查看bbox1容器的卷、卷标识符及挂载的主机目录
? Bind-mount Volume  
    ?  docker run -it -v HOSTDIR:VOLUMEDIR --name bbox2 busybox 
    ?  docker inspect -f {{.Mounts}} bbox2

docker volume ls 查看已存在的volume
docker volume inspect filename  查看卷的详细信息
两个容器共用一个存储卷,就可以共享数据
?多个容器的卷使用同一个主机目录,例如
    ? docker run –it --name c1 -v /docker/volumes/v1:/data busybox 
    ? docker run –it --name c2 -v /docker/volumes/v1:/data busybox
?复制使用其它容器的卷,为docker run命令使用--volumes-from选项
    ? docker run -it --name bbox1 -v /docker/volumes/v1:/data busybox 
    ? docker run -it --name bbox2 --volumes-from bbox1 busybox

配置容器化应用

? MariaDB:
    ? 命令行选项:使程序运行特性和程序解耦
    ? 配置文件
? 容器化方式运行MariaDB
    ? 启动容器
    ? exec -it 
? 配置容器化应用
    ? docker run 
        ? 通过自定义要运行的命令,并向传递命令行参数;
    ? 自定义镜像,将修改好的配置文件直接焙进镜像。不同环境不同的镜像
    ? 环境变量,应用程序支持变量配置,容器启动时通过加载用户传入的变量值,实现同一个镜像,不同的运行环境。但传统意义上的应用大部分都不支持次方法
        ? docker run -e
    ? 存储卷:把配置文件在本地编辑好,启动时加载特定的volume
    但这些配置方式都需要一个docker额外的平台,通过这个平台去管理docker,而不是直接通过docker
容器化时代静态已不是主流,动态才是,动态化是容器时代的一大特征。

容器和进程

? 容器:一个进程;
    ? 进程终止,必将导致容器终止;
        ? 传递终止信号:SIGTERM,SIGKILL
    ? 进程没终止:running
        ? 健康状态检测
        ? 通过重启自愈,镜像内部应该有自愈机制

配置中心:专门的键值存储系统,Redis、etcd
    程序通过watch监测,当配置中心的配置文件发生变化时从配置中心加载配置,reload配置。此时就可以达到以一应百。
    注册中心,配置中心

Docker file

Dockerfile:Dockerfile is nothing but the source code for building,制作docker镜像的指令、源码。
    ? docker build:根据docker file里的指令根据指定的某一个基础镜像来制作docker image
    ? Dokcerfile必须放在workdir目录下,build把workdir作为根,所以所有build用到的文件必须放在workdir下
    ? docker build必须基于一个基础镜像制作新的镜像,不可能完全制作一个新镜像
    ? 一个docker file中一条指令就一层镜像,所以镜像层次越少越好
    ? docker build在制作过程中会基于base image启动一个容器  
    ? dockerfile所支持的命令和制作环境都是基于基础镜像的,不是基于宿主机的
    ? 指令全大写,易于区分参数和指令,第一个指令必须是FROM
    ? dockerignore file:指定要排除的文件

dockerfile instruction

    FROM:指定docker build的basic image 
    Syntax 
        ? FROM <repository>[:<tag>] 或
        ? FROM <resository>@<digest> -->digest:镜像的校验码,
            ? <reposotiry>:指定作为base image的名称;
            ? <tag>:base image的标签,为可选项,省略时默认为latest;

    MAINTANIER:指定作者信息(以后会被替代,建议不要用)
    ? Syntax 
        ? MAINTAINER <authtor‘s detail>
        ? <author‘s detail>可是任何文本信息,但约定俗成地使用作者名称及邮件地址

    LABEL:指定作者信息
        ? Syntax: LABEL <key>=<value> <key>=<value> <key>=<value> ...

    COPY:用于Docker主机复制文件至创建的新映像文件
        ? Syntax 
            ? COPY <src> ... <dest> 或
            ? COPY ["<src>",... "<dest>"] ? <src>:要复制的源文件或目录,支持使用通配符
            ? <dest>:目标路径,即正在创建的image的文件系统路径;建议为<dest>使用绝对路径,否则,COPY指定则以WORKDIR为其起始路径;
        ? 注意:在路径中有空白字符时,通常使用第二种格式
        ?文件复制准则
            ? <src>必须是build上下文中的路径,不能是其父目录中的文件
            ? 如果<src>是目录,则其内部文件或子目录会被递归复制,但<src>目录自身不会被复制
            ? 如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且必须以/结尾
            ? 如果<dest>事先不存在,它将会被自动创建,这包括其父目录路径

    ADD
    ?ADD指令类似于COPY指令,ADD支持使用TAR文件和URL路径
    ? Syntax 
        ? ADD <src> ... <dest> 或
        ? ADD ["<src>",... "<dest>"]
    ?操作准则
        ? 同COPY指令
        ? 如果<src>为URL且<dest>不以/结尾,则<src>指定的文件将被下载并直接被创建为<dest>;如果<dest>以/结尾,则文件名URL指定的文件将被直接下载并保存为<dest>/<filename>
        ? 如果<src>是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于“tar -x”命令;然而,通过URL获取到的tar文件将不会自动展开;
        ? 如果<src>有多个,或其间接或直接使用了通配符,则<dest>必须是一个以/结尾的目录路径;如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内容将被直接写入到<dest>;

    WORKDIR
    ?用于为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD指定设定工作目录
    ? Syntax 
        ? WORKDIR <dirpath>
        ? 在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,不过,其是相对此前一个WORKDIR指令指定的路径
        ? 另外,WORKDIR也可调用由ENV指定定义的变量
        ? 例
            ? WORKDIR /var/log 
            ? WORKDIR $STATEPATH

    VOLUME
    ?用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其它容器上的卷
    ? Syntax 
        ? VOLUME <mountpoint> 或
        ? VOLUME ["<mountpoint>"] 
    ?如果挂载点目录路径下此前在文件存在,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中 

    EXPOSE
    ?用于为容器打开指定要监听的端口以实现与外部通信
    ? Syntax 
        ? EXPOSE <port>[/<protocol>] [<port>[/<protocol>] ...] 
            ? <protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议
    ? EXPOSE指令可一次指定多个端口,例如
        ? EXPOSE 11211/udp 11211/tcp
    docker run --name web1 -it --rm -P tinyweb:v0.1 创建容器的时候,需要通过-P选项来暴露EXPOSE指定的端口

    ENV
    ?用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令如ENV、ADD、COPY等)所调用
    ?调用格式为$variable_name或${variable_name}
    ? Syntax 
        ? ENV <key> <value> 或
        ? ENV <key>=<value> ...
    ? 第一种格式中,<key>之后的所有内容均会被视作其<value>的组成部分,因此,一次只能设置一个变量;
    ? 第二种格式可用一次设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<value>中包含空格,可以以反斜线()进行转义,也可通过对<value>加引号进行标识;另外,反斜线也可用于续行;
    ? 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能
    Dockerfile 中指定的变量只能在docker build中使用,docker run指定的变量在docker container中使用。

    RUN
    ?用于指定docker build过程中运行的程序,其可以是任何命令
    ? Syntax 
        ? RUN <command> 或
        ? RUN ["<executable>", "<param1>", "<param2>"] 
    ? 第一种格式中,<command>通常是一个shell命令,且以“/bin/sh -c”来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>命令停止容器
    时,此进程接收不到SIGTERM信号;
    ? 第二种语法格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起
    ,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。
    ? RUN ["/bin/sh", "-c", "<executable>", "<param1>"]
    ?注意:json数组中,要使用双引号

    CMD
    ?类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同
        ? RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时
        ? CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令其可以被docker run的命令行选项所覆盖
        ? 在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效
    ? Syntax 
        ? CMD <command> 或 作为shell的子命令运行
        ? CMD [“<executable>”, “<param1>”, “<param2>”] 或
        ? CMD ["<param1>","<param2>"]
    ?前两种语法格式的意义同RUN
    ?第三种则用于为ENTRYPOINT指令提供默认参数      

    ENTRYPOINT
    ?类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序
    ?与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定指定的程序
        ? 不过,docker run命令的--entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序
    ? Syntax 
        ? ENTRYPOINT <command>
        ? ENTRYPOINT ["<executable>", "<param1>", "<param2>"]
    ? docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用
    ? Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效
    如果CMD和ENTRYPOINT同时存在,CMD作为ENTRYPOINT的参数运行。
    在docker run时也可以通过docker -e来改变环境变量

    USER
    ?用于指定运行image时的或运行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序时的用户名或UID
    ?默认情况下,container的运行身份为root用户
    ? Syntax 
        ? USER <UID>|<UserName>
        ? 需要注意的是,<UID>可以为任意数字,但实践中其必须为/etc/passwd中某用户的有效UID,否则,docker run命令将运行失败

    HELTHCHECK 
    ? 检测容器的健康状态
    HEALTHCHECK [OPTIONS] CMD command (check container health by running a command inside the container)
    HEALTHCHECK NONE (disable any healthcheck inherited from the base image)

    [options]:
        --interval=DURATION (default: 30s)  间隔时长
        --timeout=DURATION (default: 30s)  超时时长
        --start-period=DURATION (default: 0s)  container启动之后多久开始监测
        --retries=N (default: 3)  重试次数
    退出码含意
        0: success - the container is healthy and ready for use
        1: unhealthy - the container is not working correctly
        2: reserved - do not use this exit code
    HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1
    如果容器自己没有健康检测,则可以在docker run时通过-e 定义  

    SHELL  
    改变系统默认的shell程序,因为基础镜像可能是windows。

    STOPSIGNAL
    指定系统的终止信号,默认为9

    ARG 
    在build镜像的时候,通过 --build-arg 来传递参数给ARG定义的变量,而不用事先在Dockerfile中定义好
    Syntax:ARG<name>[=<default value>]

    ONBUILD
    在Dockerfile中定义一个指令,ONBULID后面必须跟一个正常的Dockerfile指令,我们自己build的镜像可能被别人作为FROM镜像。ONBUILD后面的指令在我们build时不执行,当别人用我们的镜像build时ONBUILD才会执行。
    所以任何来路不明的镜像都不应该被运行。

以上是关于Dokcer入门及其Docker file的制作指令的主要内容,如果未能解决你的问题,请参考以下文章

Docker 入门实践

docker入门及常用命令

云原生之Dokcer实战使用Docker部署openwrt软路由

Docker入门篇之docker-compose单机编排

sh CoreOS-Dokcer使用Docker加速器,安装Docker Compose

云原生之Docker实战使用dokcer部署web端vscode