Docker是应用程序developing, shipping, 和 running的开放平台。Docker可将应用程序与应用环境分离,以便快速交付软件。使用Docker,可以像管理应用程序一样管理应用环境,利用Docker来快速传送,测试和部署代码,显著减少编写代码和在生产中运行代码之间的延迟。Docker提供了在称为容器的松散隔离环境中打包和运行应用程序的功能。其隔离、安全的特性允许用户在给定主机上同时运行多个容器。容器是轻量级的,因为它们不需要管理程序的额外负载,而是直接在主机内核中运行。这意味着可以在给定机器运行比使用虚拟机时更多的容器,甚至可以在实际虚拟机的主机中运行Docker容器!
本片文章旨在整理汇总docker的重要概念以及常用操作命令,关于更系统的理解,依旧是推荐官方tutorial.
Docker-engine采用C/S架构,包括以下组件:
server (服务器),这其实是一个守护进程,负责创建和管理Docker对象,例如Images,Containers,Networks和Volumes,对应于dockerd
client(客户端),就是负责和用户交互的CLI(command line Interface),对应于docker
REST API, 负责客户端与守护进程通信并指示其执行操作的接口。
镜像(Images)
Image是一个只读模板,其中包含有关创建Docker容器的说明;Image可以用来创建容器且一个镜像可以创造多个容器。通常,一个Image基于另一个Image,并带有一些额外的自定义。例如,您可以构建基于ubuntu Image的镜像,但剩下其他的环境配置工作是你自己自定义的。要构建自己的Image也非常简单,可以使用DockerFile语法创建Dockerfile(定义创建Image和运行Image所需的步骤)。Dockerfile中的每条指令都在Image中创建一个层(Layer)。值得注意的是,更改Dockerfile并重建Image时,仅重建已更改的那些层。因此与其他虚拟化技术相比,这是Docker Image轻量、小巧和快速的一个原因。
容器(Container)
Container是Image的可运行实例,用户可以使用Docker REST API或CLI创建,启动,停止,移动或删除容器,也可以将容器连接到一个或多个网络、将存储与之连接,甚至可以根据其当前状态创建新映像。默认情况下,一个Container与其他Container及其主机相对隔离,可以方便控制容器的网络等。Container和Image很相似,可以理解为类和对象的关系,同时需要注意Container最上面一层是可读可写的。
仓库(Repository)
集中存放Image的场所,Repository很容易和下面说的Registry(仓库注册服务器)混淆。通俗地说,它们的关系是Registry上往往存放着多个Repository,每个Repository存又放着一大堆Images,每个Image存在不同的标签(Tag);用户可以从通过注册服务器从仓库拉取(带有某个tag的)Image,从而创建Container。
Docker registries是指存储Docker Image的地方。如Docker Hub是任何人都可以使用的公共registries,这一性质类似于Github。Docker默认配置为在Docker Hub上查找你所需要的Image。注意和Repository进行区分。
UnionFS(联合文件系统)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下;UnionFS一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。UnionFS是Docker镜像的基础,镜像通过分层进行继承,基于基础镜像(images that no parent image),可以制作各种具体应用的镜像。
因此,我们会想,那基础镜像是什么呢?答案就是bootfs(boot file system),其主要包含bootloader和kernel。bootloader主要是引导、加载Kernel。这一层和典型的Linux/Unix系统是一样的,当boot加载完成之后整个内核就会在内存中了,此时内存的使用权已由bootfs交给Kernel,此时系统也会卸载bootfs。
ok,那在bootfs之上,又是什么呢?其实也和典型Linux/Unix一样,即是系统中的/dev、/proc、/bin、/etc等标准目录和文件,这些文件称为rootfs(root filesystem),是各种不同操作系统的发行版,如Centos、Ubuntu.Docker就是这样一个创建精简OS的工具,具有灵活迁移、部署的特性,因此广受业界欢迎。其rootfs可以很小,只需要包括最基本的命令、工具和程序库,因为底层直接使用Host的kernel。
# 基本帮助命令
$ sudo docker version
$ sudo docker --version
$ sudo docker info # Display system-wide information
$ sudo docker --help # help command
$ docker images
# -a 列出本地所有的镜像(含中间映像层)
# -q 只显示images 的id
# --digests 显示镜像摘要信息
# --no-trunc 显示完整的镜像信息
$ docker image ls # 同上
$ docker search key_word
# -s 列出star数不少于指定值的镜像
# --automated 只列出automated build类型的镜像
# --no-trunc 显示完整的镜像信息
$ docker pull image[:tag]
$ docker history image_id 查看镜像来源组成
$ docker rmi < image | image_id [image | image_id]>
# -f 强制删除
# 技巧之删除所有本地镜像:docker rmi -f $(docker images -qa)
$ docker commit -m=”desc” -a=”author” container_id new_image_name:[Tag] 提交新镜像
$ docker log -f container_id # 查看容器日志
$ docker run [OPTIONS] images [COMMAND][ARG...] # 新建并启动容器
--name # 指定一个该新建容器的名字
-d # 后台运行容器并返回容器id,也即启动守护式容器
-i # 以交互模式运行容器,通常与-t合用
-t # 为容器重新分配一个伪输入终端,通常与-i合用
-P # 随机端口映射
-p # 指定端口映射,有以下四种格式:
ip: hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort
# 实例
$ docker run --name [Name of container] -it --cpus=2 -v $PWD:/paddle <imagename> /bin/bash
$ docker run -d centos /bin/bash -c "while true;do echo hello;sleep 2;done"
$ docker ps [OPTIONS] # 列出docker当前在运行的容器
-a # 列出当前所有正在运行的容器+历史上运行的
-l # 显示最近创建的容器
-n # 显示最近创建的n个容器
-q # 静默模式,只显示容器编号
--no-trunc # 不截断输出
$ docker container ls --all # 同上
$ docker kill < container | container _id> # 强制停止容器
$ docker stop < container | container _id> # 停止容器
$ exit # 容器停止退出
$ Ctrl+P+Q # 容器不停止退出
$ docker attach < container | container _id> # 重新进入容器
$ docker exec -t < container | container _id> ls /tmp # 在宿主机但传入命令在容器中执行
$ docker exec -t < container | container _id> /bin/bash # 进入容器
# attach和exec区别:attach直接进入容器启动命令的终端,不会启动新进程;exec是在容器中打开新的终端,并可以启动新的进程
$ docker start < container | container _id> # 启动容器
$ docker restart < container | container _id> # 重启容器
$ docker rm [-f]< container | container _id> # 删除容器
# 技巧之删除所有容器:
docker rm -f $(docker ps -aq)
docker ps -aq | xargs docker rm
$ docker logs [-f -t –tail n] < container | container _id> # 查看容器日志
-t # 加入时间戳
-f # 跟随最新的日志打印
--tail # 显示最后几条
$ docker top < container | container _id> # 查看容器内运行的进程
$ docker inspect < container | container _id> # 查看容器内部结构
$ docker cp < container | container _id>:容器内路径 目的主机路径 # 将文件从容器中cp出,反之亦可
Docker容器产生的数据,如果不通过commit生成新的镜像,使得数据称为镜像的一部分保存下来,那么当容器删除之后,数据自然也没了。引入容器数据卷的目的便是:容器持久化;容器间继承以及数据共享。如此一来,数据卷完全独立于容器的生命周期,不会在容器删除时删除其挂载的数据。
特点:
# 容器数据卷添加方式1
$ docker run -it -v /host_absolute_path:/container_ab_path[:ro] [--privileged] Image_id_or_name
# 容器数据卷添加方式2
#(1)建立并编写DockerFile
$ mkdir mydocker
$ cd mydocker
$ vim dockerfile
FROM centos # 基于centos image再封装
VOLUME [“/dataVolumeContainer1”,” /dataVolumeContainer2”]
RUN echo “finished,---------------sucess1”
CMD /bin/bash
# (2)Build images
$ docker build -f mydocker/dockerfile -t new_image_name .
# (3)Docker run 建立容器就可发现已经挂载成功两个容器数据卷
$ docker run -it image_id
# (4)查看挂载情况
$ docker inspect container_id
# 容器继承
docker run -it --name dc01 image_id # 该镜像应该有容器数据卷
docker run -it –name doc02 –volumes-from dc01 image_id
docker run -it –name doc02 –volumes-from dc01 image_id # 如此,该三容器共享数据卷
# 首先自己编写一个DockerFile
$ cd dockerfile_dir
$ docker build -f DockerFile -t image_name .
$ docker login # 请登录dockerhub账号
$ docker tag <image_name> username/repository:tag # 建议加上tag
$ docker push username/repository:tag
https://cr.console.aliyun.com/cn-beijing/repositories, 登陆后可以获取个人加速地址
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xxxxxx.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
# 卸载
$ sudo apt-get install docker.io
$ sudo apt-get remove docker docker-engine docker.io
swarm 是一组运行 Docker 并且已加入集群中的机器(机器可以为物理机或虚拟机),简单来说就是一个docker 集群(clustering),该集群由 swarm 管理节点统一管理。特别注意管理节点和工作节点的区别与联系,一言以蔽之:管理节点是特殊的工作节点,即除了具备工作节点的功能外还具有对集群进行管理的特点。
关于虚拟机创建给出参考代码:
# 请提前安装virtualbox
$ docker-machine create --driver virtualbox myvm1
$ docker-machine create --driver virtualbox myvm2
$ docker-machine ssh myvm1 "docker swarm init" # 通过主机像虚拟机发送信息
$ docker-machine ssh myvm1 # 登录虚拟机
$ docker-machine ls # 查看有多少虚拟机
$ docker-machine env myvm1 # 查看有关节点的基本信息
关于Swarm操作常用代码:
$ docker swarm init [--advertise-addr addr] [--listen-addr node_addr] # 启用 swarm mode 并使当前机器成为swarm管理节点
$ docker info # 可以查看到swarm状态
$ docker swarm join-token -q [worker|manager] # 查看加入令牌
$ docker swarm join --token token_str host:port [--advertise-addr addr] [--listen-addr node_addr]# 当前主机加入swarm,port按照惯例一般使用2377
$ docker swarm leave [--force] # 当前主机脱离swarm
$ docker stack deploy -c <composefile> <appname> # 运行指定的 Compose 文件
$ docker stack services <appname> # 列出与应用关联的服务
$ docker stack ps <appname> # 列出与应用关联的正在运行的容器
$ docker stack rm <appname> # 清除应用,清除应用后记得leave swarm
$ docker stack ls # 列出此 Docker 主机上所有正在运行的应用,仅限于swarm情境下使用
$ docker node ls # 查看哪些主机在当前swarm中
$ docker node inspect <node ID> # 检查节点
$ docker node promote <node ID> # 将worker编程manager
$ $ docker node ps node_ps # 查看节点进程
上面的话,就可以建立一个swarm,接下来就是在这个swarm上建立service或则stack:
服务(service)实际上是“生产环境中的容器”。一项服务仅运行一个镜像,但它会编排镜像的运行方式 。扩展服务将更改运行该软件的容器实例数,并将多个计算资源分配给进程中的服务。
# service基本操作
$ docker service create --name ** -p ** --replicas number imgae:tag # 启动service
$ docker service ls # 查看service
$ docker service ps service_name # 查看service有哪些进程
$ docker service inspect service_name # 查看service详情
# service扩展
$ docker service update --replicas number service_name
$ docker service scale sevice_name=number
# 如果是镜像更新,可以参考以下代码:
$ docker network create -d overlay my-net-name
$ docker service create --name service_name --network my-net-name -p ** --replicas number imgage:tag
#update
$ docker service update --image imgage:tag --update-parallelism 2 --update-delay 10s # 更新镜像版本,update-parallelism等update参数可以在 docker service inspect 中查看
stack是在服务上面的一层,也就是说stack是由一组服务构成,而服务是由一组容器构成。stack的定义可以用yaml文件来定义:
version:"3"
services:
web:
# 将 username/repo:tag 替换为您的名称和镜像详细信息
image: username/repo:tag
deploy:
replicas:5
restart_policy:
condition: on-failure
resources:
limits:
cpus:"0.1"
memory:50M
ports:
- "80:80"
networks:
- webnet
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints:[node.role == manager]
networks:
- webnet
networks:
webnet:
docker stack deploy -c docker-compose.yml stack_name # 启动stack
docker stack ls # 查看当前集群有哪些stack
docker stack services stack_name # 查看某个stack存在哪些service
docker stack ps stack_name # 查看stack进程(这里所说进程都是指container)
LL方式使用容器名进行连接,实际上它创建了一个桥接网络,在这个网络里面,容器间可以进行通信。
docker run --link another-running-container
是指把容器添加到桥接网络(BN),这种方式则是创建了一个自定义的桥接网络,它的类型是isolated network(隔离网络),只有在这个网络里的容器才能相互通信。
$ docker network create --driver bridge net-name
$ docker network inspect net-name
$ docker run --network=net-name
dockerfile是用来构建docker镜像的构建文件,是由一系列命令和参数构成的脚本。一句话总结,Dockerfile是软件的原材料,其是面向开发的;docker image是软件的交付品,其是交付标准;docker container是软件的运行态,其是面向部署和运维。三者缺一不可,合力充当docker体系的基石。
FROM # 指明镜像基于哪个base镜像
MAINTAINER # 镜像维护者和邮箱地址
COPY # 类似ADD,拷贝文件和目录到镜像中,如COPY src dest;COPY [“src”,”dest”]
ADD # 将宿主机目录下的文件拷贝进入镜像且ADD命令会自动处理URL和解压tar压缩包
RUN # 容器构建时需要的命令
ONBUILD # 当构建一个被继承的DockerFile时运行命令,父镜像在被子继承后父镜像的onbuild被触发
.dockerignore
WORKDIR# 指定在创建容器后,终端默认登录进来的工作目录,一个落脚点
USER
CMD # 指定一个容器启动时需要运行的命令,dockerfile中可以有多个CMD命令,但只有最后一个生效,CMD会被docker run之后的参数替换。用法和RUN相似,有以下格式:
Shell格式:CMD <命令>
Exec格式:CMD [“可执行文件”,”arg1”,”arg2”,...]
参数列表格式:CMD [“arg1”,”arg2”],在制定了ENDPOINT指令后,用CMD指定具体的参数
ENTRYPOINT # 指定一个容器启动时需要运行的命令,和CMD一样,都是指定容器启动程序以及参数。Docker run之后的参数会被当做参数传递给ENTRYPOINT,之后会形成新的命令组合,这是和 CMD最大的区别。
ENV # 用来在构建镜像过程中设置环境变量,用法:ENV MY_PATH /usr/local;WORKDIR $MY_PATH。启动容器后,在容器实例中,可以通过env命令查看环境变量
EXPOSE # 当前容器对外暴露的端口
VOLUME # 容器数据卷,用于数据保存和持久化工作,用法:VOLUME [“/dataVolumeContainer1”,” /dataVolumeContainer2”]
LABEL