Docker

这是一篇2017年左右的记录, 内容可能已经过时

  • Docker的image类似于Git的repo,而docker的tag则类似于git的branch
  • 由于内核共享, Docker container 里的uid/gid是和宿主机复用的, 所以相关的鉴权系统也和系统一致.
    • 用户名可能不一致, container内可以使用自己的用户名.
    • 可以使用 --user来指定docker container内所有进程的执行身份
  • Docker 可以近似为特化的虚拟机,除了Kernel外,所有的其余部分都可以是Docker独占的。
    • 例如,可以制作完整的OS镜像,这些OS镜像除了没有内核,其余都和正常的OS是一致的。
    • Docker之间的隔离相比VM要浅一些,可能存在一些安全问题;另一方面,VM则由于可攻击面更大,也有安全问题
  • Docker可以说是一个Utility, 并没有自创新技术,所以Docker中的技术主体为Docker-Engine,它只是驱动整个体系高效的运转.
  • Docker是通过Kernel的功能实现功能上的"隔离"
    • 对于docker内的进程,它认为自己在独立的主机中,且看不到外部的进程
    • 对于宿主机,所有docker内的进程都是客观存在的
  • Docker使用Linux的Namespace进行隔离,具体包括
    • 文件系统: 每个容器都有自己的root文件系统
    • 进程隔离: 每个容器都有独立的用户空间
    • 网络隔离: 每个容器都在自己独立的子网中,这个子网宿主也不能访问,必须将其内部的端口映射到宿主的端口上才能使用.
    • 资源隔离: 每个容器的CPU/内存资源等都是隔离的.
    • CoW:根文件系统是写时复制的,不写入新数据的话不会创建文件副本.
  • Docker镜像: 可以认为Docker镜像是一个类似于bootable-iso一样的文件系统.
    • Docker镜像是只读的,启动后仍然是只读的.
    • 文件系统是可以分层叠加的,例如,ubuntu镜像提供了rootfs, 后续的镜像就可以基于rootfs继续添加文件.
      • Docker镜像的典型文件系统层为: bootfs-rootfs-user_files
    • 镜像启动后变成了container实例,每个实例都有自己的一个可读写层.对镜像内的文件系统IO时,若有写入,会写时复制到可读写层中,之后,该容器只会使用写时复制的版本,镜像内的只读版本仍然存在,但是不会被使用了;换言之,如果不写入数据,读取的永远是镜像内的数据.
    • Container实例常可被称为"镜像栈",即启动若干镜像,逐层累积起来,最后再添加一个读写层.
  • Docker的标准IO流都会被自动被记录到日志中. 可以用 docker logs container_id来查询对应的stdout
  • Docker镜像内可以启动bash等,从而看起来像虚拟机一样提供用户接口.
  • Docker Community Edition
    • 直接看Docker-CE Ubuntu即可
    • Mac 及 Windows的Docker都是通过中间的一个虚拟机实现的.
    • Edge release和Toolbox都是depreciated.
  • Docker 内置了和Github类似的DockerHub(官方), 提供类似服务的服务器称为Registry
    • 本地创建的镜像可以通过tag系统和Registry映射(相当于 git remote add),docker tag local_image username/reponame:tagname
  • Docker-Engine为CS架构
    • Server: 提供核心服务的daemon dockerd, dockerd 自身会暴露出REST API
    • Client: CLI工具,即docker指令,该指令内部通过REST API与dockerd交互.
    • 因此,WIN/MAC的Docker中,虚拟机中仅安装Server,客户机中仅安装Client.
  • Docker中的常见元素:
    • Dockerfile : 相当于编译脚本, 用于生成 Image
    • Image : 一个只读镜像, 用于初始化Container
    • Container: 实例化的Image, 销毁时会摧毁所有没有
  • TODO: 可以在了解Docker之后看Document -> Develop With Docker -> Develop images

Dockerfile

  • Dockerfile 相当于一个执行脚本.
    • 创建一个FROM镜像的实例
    • 每一个指令都会对上一步启动的实例进行修改, 并保存为一个新的"中间镜像",再启动这个"中间镜像",作为下一步待修改的实例.换言之,每一条指令都对应了一个"镜像层".(Docker build的日志能很好的体现这个过程)
      • Dockerfile中的每一个指令都会产生一个自己对应的缓存,当指令被修改时,只有后续的指令会被重新构建.利用这一特性,可以写一些基础模板dockerfile,build之后作为其他镜像的FROM,加速构建过程.
      • 尽管只有最后一步输出的镜像是有用的,中间镜像也会被缓存,以加速build,这可能导致一些麻烦,可以通过docker build --no-cache来禁用中间镜像的缓存,强制从头开始执行.
      • 一个典型的避免cache的好技巧是在头部添加ENV MIRROR_REFRESH_DATE xxxx
          1. 这个值可以供容器查询镜像的构建时间.
          1. 修改这行代码会强迫后续的所有指令都不使用缓存.
    • 若脚本没有执行完成,那么build的产物是最后成功执行的那个镜像,此时一般可以交互式的启动这个镜像,并在其中进行debug,判断Dockerfile执行失败的原因.
  • 没有FROM,或者FROM scratch的image被称为baseimage
  • 指令均为大写,例如FROM,RUN

DOCKERFILE command

  • RUN xxx , 在中间容器实例中执行/bin/sh -c xxx
  • ENV name value, 在构建环境及容器实例中创建环境变量,(这个环境变量也可以被DOCKERFILE自身使用)
  • EXPOSE num, 将num加入可供映射的网络端口列表,该端口必须在docker run时进行映射才能使用.
  • CMD [xxx,yyy,zzz], 镜像启动默认参数,在镜像被docker run启动时,若没有给出运行参数,则会自动将xxx yyy zzz附加到末尾
  • ENTRYPOINT [xxx,yyy,zzz,THE_CMD], docker run输入的THE_CMD实际会附加到这里被container执行.( 这个特性是可以被指令强制覆盖的)
  • WORKDIR, 相当于cd,切换工作目录,最后设置的WORKDIR将作为ENTRYPOINT的执行目录
  • USER, 设定启动用户,默认值为root
  • VOLUME [path1,path2], 创建挂载点及对应的虚拟卷
    • 虚拟卷是和镜像绑定的,每一个容器实例都会在启动时自动挂载对应的虚拟卷.换言之,镜像的所有实例之间都共享虚拟卷.
    • 使用虚拟卷主要是为了在容器中实时的共享文件,相比之下, 在容器中对非虚拟卷的操作都是local的,无法共享出去.(特别的,镜像X可以通过启动docker run --volume-from y挂载镜像y虚拟卷)
    • 如果想把宿主的文件挂载到容器中, 可以在docker run时通过-v local_path:container_path创建,-v可以覆盖容器内的挂载关系(包括虚拟卷)
  • ADD source dest, 将宿主机的文件cp到container中,这里源还可以是http://../a.zip这样的路径. 如果源是tar.gz等压缩文件,还会被解压.
    • ADD会强制刷新缓存,执行到ADD之后,后续的指令一定不会使用之前的缓存.
  • COPY source dest,行为和ADD类似,但是不会做自动解压的工作.
  • LABEL,为镜像添加描述信息
  • STOPSIGNAL,容器停止时像容器内进程发送的信号,即kill的参数
  • ARG x=yyy,用户在build时,可以通过docker build --build-arg x=value传入参数,如果没有传入,使用yyy作为默认值,注意,由于所有docker的调用都会被日志系统明文保存,所以不要传递密码等信息作为参数.
  • ONBUILD DOCKER_CMD,DOCKER_CMD会在当前dockerfile以及它的子镜像中被执行,例如,一个镜像中有FROM:xxx,那么在build时,它会先自动执行xxx中的ONBUILD,注意,ONBUILD对孙镜像是无效的.

    mmand Sheet

    
    ## List Docker CLI commands
    docker
    docker container --help

Display Docker version and info

docker –version
docker version
docker info # 主要用于查看 image数和container数
docker stats # 查看所有容器的运行状态

Execute Docker image

注意 image_name后面都可以加`:`指定tag

docker run hello-world # 启动并自动attatch到container内

docker run -i -t

-i 启用container的stdin

-t 为container添加一个虚拟tty,相当于为docker提供一个stdout和stdin,并映射到到host的对应项目.

一般而言,如果需要与容器interactive,这两个选项是必须的.(当然,docker内还需要提供一个cli界面程序连接到tty,如shell)

docker run -e # 添加环境变量
docker run -p # 设定端口映射
docker run -u # 设定启动用户
docker run -d # 启动且不attatch到container内, 相当于后台运行
docker -run –name xxxx # 启动时为container 起一个名字,最好是有一个

docker run 执行的程序在return后容器会自动EXIT,因此,run启动的程序一般必须得是常驻不return的.

docker pull image_name:tag # 拉取指定的image
docker start container_id # 启动一个EXIT状态的container, start 不会自动将终端切入到container中,所以需要 docker attach container_id
docker create xxx # 创建而不启动container

docker exec # docker run参数类似,是在已经启动的容器中执行新的程序

docker stop/kill: container_id # 停止容器

docker rm # 删除容器

List Docker images

docker image ls

List Docker containers (running, all, all in quiet mode)

docker container ls
docker container ls –all
docker container ls -aq

docker build -t friendlyhello . # Create image using this directory's Dockerfile 若没有指定-t,那么会使用latest
docker run -p 4000:80 friendlyhello # Run "friendlyname" mapping port 4000 to 80
docker run -d -p 4000:80 friendlyhello # Same thing, but in detached mode
docker container ls # List all running containers
docker container ls -a # List all containers, even those not running
docker container stop <hash> # Gracefully stop the specified container
docker container kill <hash> # Force shutdown of the specified container
docker container rm <hash> # Remove specified container from this machine
docker container rm $(docker container ls -a -q) # Remove all containers
docker image ls -a # List all images on this machine
docker image rm <image id> # Remove specified image from this machine
docker image rm $(docker image ls -a -q) # Remove all images from this machine
docker login # Log in this CLI session using your Docker credentials
docker tag <image> username/repository:tag # Tag <image> for upload to registry
docker push username/repository:tag # Upload tagged image to registry
docker run username/repository:tag # Run image from a registry

list container status

docker ps -a

list apps in container

docker top container_id