docker

/ 默认分类 / 0 条评论 / 112浏览

一.基本概念

  1. docker镜像

镜像是一种只读的模板文件,其中包含了容器程序运行所需的文件和环境参数,是容器运行的基础

  1. docker容器

容器类似一个沙箱,创建了一个隔离的环境,是从镜像模板创建出来的程序应用实例,可以理解为一个简易的linux系统,其中运行着某个程序进程,不同的容器之间相互隔离,创造出了一种独立的环境,容器可以启动,停止,删除等操作

ps:docker镜像是只读的,通过镜像创建运行一个docker容器后,会在镜像这个只读层上创建一个可写层,这样容器中的程序实例就可以进行数据存储交互了,但是最终都不会影响到镜像本身

二.docker与linux内核

docker引擎之所以可以实现虚拟化,其实都要归结于linux提供的系统支持,linux内核在3.8版本之后提供了一种服务隔离技术namespace,其中包括PID namespace,User namespace,Ip namespace等等,对服务进行了完全的隔离支持。

另外,docker还依赖与linux中cgroup,来进行资源管理,关于namespace和cgroup的详细知识,我还没有深入探究过,有时间再好好看看。

linux3.8之后可以在;/proc/[pid]/ns目录下看到进程的namespace

可以看到,每个进程的namespace包括ipc,net网络,pid号,user用户名等等,在不同的结构上使用namespace进行隔离,可以看到宿主机的进程,使用的都是一样的,都是host主机的namespace,但是docker中的容器进程使用的就是不同的namespace,进而实现隔离,当然在docker run启动容器的时候可以指定不同的namespace部分使用指定的,比如

docker run -ti --net container:664562841f30 myredis ifconfig //新启动的这个容器,就会直接加入到ID=664562841f30的容器,也就是我们前面的创建的 Python 应用容器(PID=10444)的 Network Namespace 中

如果指定的是–net=host  ,那么说明新启动的容器使用的是宿主机的Network Namespace,它会和宿主机上的其他普通进程一样,直接共享宿主机的网络栈。  

下面是具体的查看操作:

[root@zh_vm nacos]# ps -ef | grep -E 'crond|nacos'
root        689      1  0 12:33 ?        00:00:00 /usr/sbin/crond -n
root       4162      1  7 23:14 pts/0    00:00:32 /usr/local/jdk1.8/jdk1.8.0_192/bin/java -Xms512m -Xmx512m -Xmn256m -Dnacos.standalone=true -Dnacos.member.list= -Djava.ext.dirs=/usr/local/jdk1.8/jdk1.8.0_192/jre/lib/ext:/usr/local/jdk1.8/jdk1.8.0_192/lib/ext -Xloggc:/home/down/nacos/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -Dloader.path=/home/down/nacos/plugins/health,/home/down/nacos/plugins/cmdb -Dnacos.home=/home/down/nacos -jar /home/down/nacos/target/nacos-server.jar --spring.config.additional-location=file:/home/down/nacos/conf/ --logging.config=/home/down/nacos/conf/nacos-logback.xml --server.max-http-header-size=524288 nacos.nacos
root       4532   3291  0 23:22 pts/0    00:00:00 grep --color=auto -E crond|nacos
[root@zh_vm nacos]# ll /proc/689/ns
total 0
lrwxrwxrwx. 1 root root 0 Jul 17 23:20 ipc -> ipc:[4026531839]
lrwxrwxrwx. 1 root root 0 Jul 17 23:20 mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 Jul 17 23:20 net -> net:[4026531956]
lrwxrwxrwx. 1 root root 0 Jul 17 23:20 pid -> pid:[4026531836]
lrwxrwxrwx. 1 root root 0 Jul 17 23:20 user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0 Jul 17 23:20 uts -> uts:[4026531838]
[root@zh_vm nacos]# ll /proc/4162/ns
total 0
lrwxrwxrwx. 1 root root 0 Jul 17 23:21 ipc -> ipc:[4026531839]
lrwxrwxrwx. 1 root root 0 Jul 17 23:21 mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 Jul 17 23:21 net -> net:[4026531956]
lrwxrwxrwx. 1 root root 0 Jul 17 23:21 pid -> pid:[4026531836]
lrwxrwxrwx. 1 root root 0 Jul 17 23:21 user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0 Jul 17 23:21 uts -> uts:[4026531838]
[root@zh_vm nacos]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
ed282fbe617d        redis               "docker-entrypoint..."   2 weeks ago         Up 10 hours         0.0.0.0:6379->6379/tcp              myredis
844b3aebcb2c        383867b75fd2        "docker-entrypoint..."   3 months ago        Up 10 hours         0.0.0.0:3306->3306/tcp, 33060/tcp   mysql01
[root@zh_vm nacos]# docker inspect myredis |grep  Pid
            "Pid": 1737,
            "PidMode": "",
            "PidsLimit": 0,
[root@zh_vm nacos]# ll /proc/1737/ns
total 0
lrwxrwxrwx. 1 polkitd input 0 Jul 17 19:36 ipc -> ipc:[4026532572]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 12:33 mnt -> mnt:[4026532570]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 12:33 net -> net:[4026532575]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 19:36 pid -> pid:[4026532573]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 23:00 user -> user:[4026531837]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 19:36 uts -> uts:[4026532571]
[root@zh_vm nacos]# docker inspect mysql01 |grep  Pid
            "Pid": 1754,
            "PidMode": "",
            "PidsLimit": 0,
[root@zh_vm nacos]# ll /proc/1754/ns
total 0
lrwxrwxrwx. 1 polkitd input 0 Jul 17 23:23 ipc -> ipc:[4026532636]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 12:33 mnt -> mnt:[4026532634]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 12:33 net -> net:[4026532639]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 23:23 pid -> pid:[4026532637]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 23:23 user -> user:[4026531837]
lrwxrwxrwx. 1 polkitd input 0 Jul 17 23:23 uts -> uts:[4026532635]

三.docker的基本架构

  1. docker使用的是传统的client-server架构方式,用户通过docker client与docker daemon建立通信,然后将请求发送给docker处理,docker后端是松耦合的结构,不同的模块负责不同的功能。

    docker首先会启动后端daemon程序,其中会完成的工作包括:Docker容器的配置信息、检测系统支持及用户权限、配置工作路径、加载并配置graphdriver、创建Docker网络环境、创建并初始化镜像数据库、创建容器管理驱动、检测DNS配置和加载已有Docker容器等

  2. 我们在linux中执行docker的相关命令时,主要执行的是api/client/cli.go,cli通过对命令进行解析,一般是通过反射找到需要执行的方法,然后执行该方法,最终cli准备好本次请求,通过请求docker daemon的server api,让docker daemon来执行相应操作然后获取响应的结果

ps:下面是完整的client执行步骤
(1) docker run命令开始运行,用户端的Docker进入client模式,开始了3.3.1节讲述的client工作过程;
(2) 经过初始化,新建出了一个client;
(3) 上述client通过反射机制找到了CmdRun方法。CmdRun在解析过用户提供的容器参数等一系列操作后,最终发出了这样两个请求:

"POST", "/containers/create? "+containerValues //创建容器  
"POST", "/containers/"+createResponse. ID+"/start" //启动容器

至此,client的主要任务结束。

四.docker和虚拟机

虚拟机是一种传统的虚拟化技术,其是对硬件和软件的完全虚拟化,主要原理如下:

下面是docker的虚拟化:

docker的启动速度更快,可移植性更强,性能要求较低,单机可以运行成百上千个容器

五.docker exec和docker run

文档地址

docker exec就是在已经运行的容器中执行命令

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

比如我们使用的

docker exec -it mysql01 /bin/bash

就是在运行的mysql01容器中执行bash,即交互shell
其实按照前面我们说的,其实就是使用该容器的namespace环境来运行指定的程序

官方文档中有这样一个注意点:

COMMAND 应该是可执行文件,链接或引用的命令将不起作用。示例:docker exec -ti my_container "echo a && echo b"不会工作,但docker exec -ti my_container sh -c "echo a && echo b"会。

文档地址

docker run和上面的docker exec一样,都可以在容器中运行一个指定的程序命令
不同的是,docker run是新创建一个容器,然后再容器中运行,docker exec是在现有的正在运行的容器中执行程序命令

也就是说docker run适用于在没有其他容器运行的情况下,您想要创建一个容器,并且要启动它,然后在其上运行一个程序命令。