Docker详解

文章目录

  • 写在篇前
  • 基本概念
      • Docker-Engine
      • Docker三要素
      • Docker-registries
      • UnionFS
  • 常用命令
      • 帮助命令
      • 镜像命令
      • 容器命令
      • 容器数据卷
      • 镜像发布
      • 镜像加速
      • 安装与卸载
  • 高级知识
      • Swarm
          • service
          • stack
      • 容器网络
          • Legacy Linking
          • Brige Network
  • DockerFile

写在篇前

  Docker是应用程序developing, shipping, 和 running的开放平台。Docker可将应用程序与应用环境分离,以便快速交付软件。使用Docker,可以像管理应用程序一样管理应用环境,利用Docker来快速传送,测试和部署代码,显著减少编写代码和在生产中运行代码之间的延迟。Docker提供了在称为容器的松散隔离环境中打包和运行应用程序的功能。其隔离、安全的特性允许用户在给定主机上同时运行多个容器。容器是轻量级的,因为它们不需要管理程序的额外负载,而是直接在主机内核中运行。这意味着可以在给定机器运行比使用虚拟机时更多的容器,甚至可以在实际虚拟机的主机中运行Docker容器!

  本片文章旨在整理汇总docker的重要概念以及常用操作命令,关于更系统的理解,依旧是推荐官方tutorial.

基本概念

Docker-Engine

  Docker-engine采用C/S架构,包括以下组件:

  • server (服务器),这其实是一个守护进程,负责创建和管理Docker对象,例如Images,Containers,Networks和Volumes,对应于dockerd

  • client(客户端),就是负责和用户交互的CLI(command line Interface),对应于docker

  • REST API, 负责客户端与守护进程通信并指示其执行操作的接口。

Docker详解_第1张图片

Docker三要素

  • 镜像(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详解_第2张图片

Docker-registries

  Docker registries是指存储Docker Image的地方。如Docker Hub是任何人都可以使用的公共registries,这一性质类似于Github。Docker默认配置为在Docker Hub上查找你所需要的Image。注意和Repository进行区分。

UnionFS

  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

  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)实际上是“生产环境中的容器”。一项服务仅运行一个镜像,但它会编排镜像的运行方式 。扩展服务将更改运行该软件的容器实例数,并将多个计算资源分配给进程中的服务。

# 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是由一组服务构成,而服务是由一组容器构成。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)

容器网络

Legacy Linking

 LL方式使用容器名进行连接,实际上它创建了一个桥接网络,在这个网络里面,容器间可以进行通信。

  • 运行一个container
  • 通过container name 连接到另外一个正在运行的container

  docker run --link another-running-container

Brige Network

 是指把容器添加到桥接网络(BN),这种方式则是创建了一个自定义的桥接网络,它的类型是isolated network(隔离网络),只有在这个网络里的容器才能相互通信。

  • 创建一个自定义桥接网络
  • 启动容器,使容器运行于一个或多个桥接网络之中,只有同一个桥接网络的容器之间可以通信
$ docker network create --driver bridge net-name
$ docker network inspect net-name
$ docker run --network=net-name

DockerFile

  dockerfile是用来构建docker镜像的构建文件,是由一系列命令和参数构成的脚本。一句话总结,Dockerfile是软件的原材料,其是面向开发的;docker image是软件的交付品,其是交付标准;docker container是软件的运行态,其是面向部署和运维。三者缺一不可,合力充当docker体系的基石。

  • 构建三步骤
    • 编写dockerfile
    • docker build
    • docker run
  • 基本规范
    • 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
    • 指令按照从上到下,顺序执行
    • #表示注释
    • 每条指令都会创建一个新的镜像层,并对镜像进行提交
  • DockerFile执行顺序
    • docker从基础镜像运行一个容器
    • 执行一条指令并对容器做出修改
    • 执行类似docker commit的操作提交一个新的镜像层
    • docker再基于刚提交的镜像运行一个新容器
    • 执行dockerfile中的下一条指令直到所有的指令都执行完
  • 保留字指令
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 

Docker详解_第3张图片

你可能感兴趣的:(docker)