什么场景适合使用Docker
-1 VM构建于Hypervisor上,并内置一套完整的操作系统,磁盘耗用和调度耗用较大,主要用于隔离不同的用户,安全级别较高;Docker构建于Docker Daemon上,直接共享host上的kernel service,并不需要内置操作系统,因此更节省磁盘空间和启动性能损耗,主要用于隔离不同的应用(前端服务器,后端服务器,数据库,缓存服务器等),属于host上不同的process;
-2 docker image是一个包含app运行所有需要文件的只读可执行包,包含:app source code, runtime lib, env vars, config file,而这些文件通过dockerfile进行指定,dockerfile同时会指定镜像操作指令,容器启动指令;通过docker启动image的时候会分配一系列的资源,添加一个可编辑层记录状态,从而成为docker container;
-3 docker可以将不同环境的dependency差异降低到最低;Docker可以实现秒级启动,可根据业务流量及时进行水平扩容和缩容;
实现docker的核心技术
-1 namespace:原本是Linux用于分离进程树、网络接口、存储挂载点、进程间共享资源的命名空间,这样进程 、网络和文件系统可以做到相互独立存在,运行互不影响; 不同命名空间下的进程只能看到自己的系统视图
docker通过namespace实现了container的网络隔离,同时通过bridge docker0实现host内container间的相互通信,然后依赖Linux iptables实现client对host:port的访问转发到内部具体的container-ip:port;
对于k8s而言,一个pod内部可能运行多个docker,并且多个docker需要共享同一个namespace,因此创建了一个base docker用于在同一个pod内的多个docker之间共享namespace,该base docker的生命周期与pod一致;
-2 control groups:通过namespace,docker可以实现volume和network的相互隔离;但是CPU,memory,networking i/o,disk i/o等物理资源并不受namespace的影响,而Linux CGroup则用于实现同一个host上物理资源的隔离管理,为一组进程分配资源,实现resource limiting, control, accouting, prioritization等功能;
-3 union file system:AUFS的技术可以让多个只读文件目录union成一个新的目录,并且可以对这个新的目录进行读写操作,也是docker的基础实现依赖;同时,多层镜像结构可在多个镜像之间共享,提升使用效率;因此docker容器相当于docker镜像加上可写层,可写层上记录docker 容器的运行和配置状态;
下一代容器技术podman,通过fork/exec创建container,也就是父子进程关系,而docker是client / server模式;
安装docker
MacOS上使用homebrew安装docker(CentOS上使用yum / apt-get)
% brew cask install docker
基于dockerfile文件创建image
自定义镜像一般会有几个步骤,CMD之前的每一条指令都会创建一个temp image,也就是AUFS的设计逻辑,从而减小总体的体积占用:
-1 通过FROM指定基础依赖镜像;
-2 通过WORKDIR创建container环境的文件目录;
-3 通过COPY将host上的文件复制到container环境,.dockerignore可指定exception;
-4 通过CMD或者ENTRYPOINT在container环境执行命令,启动service;
-5 通过EXPOSE指定container port,该port需要与host port绑定才可访问;
1 # 指定构建custom image所使用的base image; 2 # 必须是dockerfile的第一条命令; 3 # base image可以是本地仓库也可以是线上仓库; 4 # tag或者digest如果不写,则使用latest版本; 5 FROM <image>:<tag|digest> 6 7 # 设置构建信息 8 MAINTAINER ychen yu.chen@example.com 9 10 # 在host当前目录下创建临时文件, 11 # 并在container中映射为指定的/var/www/html目录; 12 VOLUME .:/var/www/html 13 14 # 设置环境变量 15 ENV DEBUG=ON 16 17 # 在custom image生成过程中执行特定命令,生成temp image,可以有多个; 18 # temp image会被缓存以便下次构建使用,--no-cache可以禁用; 19 RUN apt-get update 20 RUN apt-get install -y nginx 21 22 # 添加打包好的目标可执行文件 23 ADD <target_jar> 24 25 # 指定container启动后缺省执行的命令,如java -jar target_jar 26 ENTRYPOINT <command> 27 # 指定custom image运行启动时执行命令所需要的参数,只能有一个; 28 # image构建完成后执行,不会生成新的temp image; 29 CMD <command> 30 31 # 设置custom image的运行时监听端口 32 EXPOSE <port>
一般有两种容器主进程启动方式
-1 基于shell
ENTRYPOINT node app.js
-2 基于exec
ENTRYPOINT [“node”, “app.js”]
基于shell的启动方式,容器是先启动/bin/sh的shell进程,再fork启动目标node进程;基于exec的启动方式,容器是直接fork启动目标node进程,因此推荐使用后者;
-1 获取docker基本信息
% docker info
% docker version
-2 image操作命令
列出本地所有的image列表
% docker image ls
从远程仓库拉取指定的image:(通过docker registry可以创建私有仓库)
% docker image pull {image-name}
基于当前目录的dockerfile文件创建指定名字和版本的image:
% docker image build -t {image-name}:{version} .
% docker image rm {image-name}
-3 container操作命令
列出本地所有的container列表:
% docker container ls -a
从本地或远程仓库查找image,指定proxy端口,创建 / 启动 / 运行一个container:
% docker container run -p {host-port}:{container-port} {image-name}
% docker container rm {container-id}
% docker container kill {container-id}
% docker container start {container-id}
% docker container stop {container-id}
% docker container logs {container-id}
将指定container上的文件拷贝到本地:
% docker container cp {container-id}:{file-path} .
进入指定的container,并执行指定的命令:
% docker container exec -it {container-id} {cmd}
查看docker资源占用情况
$ docker stats --no-stream
$ docker top $(docker ps -ql) -o pid,stat,ppid
查看docker跟CPU和内存资源相关的启动参数
$ docker run --help | egrep ‘cpu|memory’
限制已经运行的docker的cpu占用率为50%
$ docker update --cpus "0.5" $(docker ps -ql)