一、什么是Docker
Docker简介
Docker是基于Go语言并遵从并遵从 Apache2.0 协议的开源应用容器引擎。让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。
Docker与传统虚拟机的比较
更高效的利用系统资源 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。 更快速的启动时间 传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。 一致的运行环境 由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而Docker镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。 持续交付和部署 对开发和运维人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。 更轻松的迁移 由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。 更轻松的维护和扩展 Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。
Docker对于不同用户的作用
对于开发人员可以让开发环境更贴近生产环境,还能一起打包快速部署。由于占用资源底,可以极大的价格低企业生产成本。利用docker的隔离性将整个服务拆分成多个单服务(微服务架构) 对于CTF选手可以快速实现漏洞环境的复现,可以更加专注于漏洞原理的研究,减少在环境配置等环节的耗时,帮助我们更快的提升自己。
二、Docker架构
Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。 Docker 容器通过 Docker 镜像来创建。 容器与镜像的关系类似于面向对象编程中的对象与类。
三个基本概念
镜像:Docker 镜像就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。 容器:镜像和容器的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。 仓库:仓库可看成一个代码控制中心,用来保存镜像。
Docker架构图
Docker Client
Docker Client 是 Docker 架构中用户用来和 Docker Daemon 建立通信的客户端。用户使用的可执行文件为 docker,通过 docker 命令行工具可以发起众多管理 container 的请求。Docker Client 发送容器管理请求后,由 Docker Daemon 接受并处理请求,当Docker Client 接收到返回的请求相应并简单处理后,Docker Client 一次完整的生命周期就结束了。当需要继续发送容器管理请求时,用户必须再次通过docker 可执行文件创建 Docker Client。
Docker Daemon
Docker Daemon 是 Docker 架构中一个常驻在后台的系统进程,功能是:接受并处理 Docker Client 发送的请求。该守护进程在后台启动了一个 Server,Server 负责接受 Docker Client 发送的请求;接受请求后,Server 通过路由与分发调度,找到相应的 Handler 来执行请求。
Docker Registry
Docker Registry 是一个存储容器镜像的仓库。而容器镜像是在容器被创建时,被加载用来初始化容器的文件架构与目录。在 Docker 的运行过程中,Docker Daemon 会与 Docker Registry 通信,并实现搜索镜像、下载镜像、上传镜像三个功能,这三个功能对应的 job 名称分别为 ”search”,”pull” 与 “push”。 其中,在 Docker 架构中,Docker 可以使用公有的 Docker Registry,即大家熟知的 Docker Hub,如此一来,Docker 获取容器镜像文件时,必须通过互联网访问 Docker Hub;同时 Docker 也允许用户构建本地私有的 Docker Registry,这样可以保证容器镜像的获取在内网完成。
三、Docker安装
下面以centos7举例,其他系统安装类似,不明白的地方还可以查看帮助文档
- 检查内核版本
docker要求Linux内核版本不高于3.10,可以通过uname -r查看。除此之外centos要求centos7及以上 我的内核版本刚好3.10 - 卸载掉原有版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
最后是这样的就说明可以了 3. 安装依赖工具以及设置仓库
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
最后配置完是这样的。 4. 安装docker引擎
sudo yum install docker-ce docker-ce-cli containerd.io
安装结束是这样的,如果想安装特定版本的docker可以在帮助文档查看安装步骤,默认是安装的最新版。 5. 安装结束后即可启动
sudo systemctl start docker
查看是否安装成功
docker version
docker info
这两条命令将显示docker的相关信息.
最后更换阿里云的镜像
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://3i9hdziw.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
帮助文档
四、Docker镜像(Image)
docker images
查看镜像
docker images
-a,--all 展示所有的镜像
-q,--quiet 只显示镜像id
docker search
搜索镜像
docker search mysql -f=STARS=3000
docker pull
下载镜像(默认下载最新版latest)
docker pull mysql
docker pull mysql:5.4
docker rmi
删除镜像
-f,--force
docker rmi name/id
docker rmi name1/id1,name2/id2
docker rmi -f $(docker images -aq)
五、Doker容器(Container)
容器操作
docker run
创建一个容器并启动然后在容器内执行一条命令
docker run [option] name [command [arg1,arg2,...]]
--name="Name"
-d
-it
-p(小写)
-P(大写)
-e
--env-file=[]
-m
-v,--volume
docker create
创建一个容器(不启动)。参数基本上和run一样
exit
在容器内输入exit退出容器
Ctrl + p + q
退出容器但不停止容器
docker ps
查看运行的容器
-a,--all
-q,--quiet
-n,--last int
-f,--filter
docker rm
删除容器
-f,--force
-v,--volumes
docker rm name/id
docker rm $(docker ps -a --filter "exited=1" -q)
docker pause/unpause
暂停/继续运行容器
docekr start/stop/restart
运行/停止/重启容器
docker kill
强制停止容器 注:docker容器必须要有一个前台进程,如果没有前台进程进行,容器会被认为空闲就会自动退出
[root@192 ~]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@192 ~]
3e6eed9e9a0db00cd8842f3ca5c37c29eecd7b573321ec33ebd21ccf48dba5a3
[root@192 ~]
CONTAINER ID IMAGE COMMAND CREATED STATUS
3e6eed9e9a0d centos "/bin/bash" 23 seconds ago Exited (0) 22 seconds ago
[root@192 ~]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@192 ~]
d4945eb1afa174629d573c0c8be9d3a9955adb1818e1b768dc129aad2bc3953a
[root@192 ~]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
d4945eb1afa1 centos "/bin/bash" 3 seconds ago Up 3 seconds
可观察到当docker容器指定后台运行时必须有一个前台进程,否则系统在运行后就自动退出了。
容器管理
docker logs
查看容器日志
-f,--follow
-n,--tail
-t,--timestamps
docker top
查看容器进程信息
docker inspect
查看镜像的元数据
docker exec
在正在运行的容器中执行一条新的命令(常用)
docker exec [options] container command [args]
-d,--detach
-e,--env list
-i,--interactive
-t,--tty
-w,--workdir string
[root@laptop-670cig77 ~]
[root@d4945eb1afa1 /]
[root@laptop-670cig77 ~]
/root
[root@laptop-670cig77 ~]
docker attach
docker attach name/id 进入容器。
docker attach 与docker exec的区别: docker attach 进入原有的终端 docker exec新建一个终端
docker cp
docker cp source dest,从容器内拷贝文件到主机
docker stats
查看cpu状态
六、Docker文件系统及分层技术
Linux文件系统
Linux系统至少包含两个文件系统
- Boot File System(bootfs) ----> Boot Loader、Kernel
- Root File System(rootfs)-----> /dev、/proc、/bin…
Linux系统在启动时第一步运行Boot Loader,然后载入内核Kernel,最后卸载掉Boot File System,释放内存。第二不载入Root File System,这个就是我们常见/bin,/proc等文件。 不同发行版系统在Boot File System都是一样的,只有Root File System在不同发行版之间有所不同。 因此所有docker容器都共享主机系统的Boot File System,每个容器只需要包含Root File System,它们的的缩略版(所以我们安装的镜像里面有些命令可能找不到)构成了docker基础镜像。
UnionFS(联合文件系统)
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。UnionFS联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承. 基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
分层理解
docker镜像是实质上都是由一层一层文件系统叠加构成的,就像是面向对象里面的类一样,这样能极大的提高资源共享。如上图最开始的bootfs由直接由宿主机提供,然后上面根据功能的不同依次叠加不同的层级,这也是为什么虚拟机里面的镜像一般都是几个G,而docker里面才几十k到几百兆不等。因为一个精简的镜像每一层都可以做到很小,只要能保证最基础的工具就可以了。当启动一个容器时,只要在镜像层上面加一个可写层就行了。 镜像和容器的区别:容器层就是在镜像层上面多了一个可写层。
commit操作
docker commit [option] container [name[:tag]] 将容器打包成一个新的镜像
-a,--author
-m,--message
eg:
[root@192 ~]
7b14efe8907456d93316bb815edd4d41d908ce3ce069fb31b24566dce794466f
[root@192 ~]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b14efe89074 httpd "httpd-foreground" 17 seconds ago Up 16 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp apache
[root@192 ~]
<html><body><h1>It works!</h1></body></html>
[root@192 ~]
root@7b14efe89074:/usr/local/apache2
root@7b14efe89074:/usr/local/apache2/htdocs
index.html
root@7b14efe89074:/usr/local/apache2/htdocs
root@7b14efe89074:/usr/local/apache2/htdocs
<html><body><h1>my apache\!</h1></body></html>
root@7b14efe89074:/usr/local/apache2/htdocs
exit
[root@192 ~]
sha256:b5adac00c770576a5f09c2352d49cee3012aa11495e2e286a0e744c7507ba7d9
[root@192 ~]
REPOSITORY TAG IMAGE ID CREATED SIZE
myapache latest b5adac00c770 7 seconds ago 144MB
httpd latest dabbfbe0c57b 4 weeks ago 144MB
hello-world latest feb5d9fea6a5 4 months ago 13.3kB
centos latest 5d0da3dc9764 4 months ago 231MB
[root@192 ~]
2394848be0058e6087a3d077bfde0686b7e5561411d8082968073c65cc1fcd06
[root@192 ~]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2394848be005 myapache "httpd-foreground" 4 seconds ago Up 3 seconds 0.0.0.0:81->80/tcp, :::81->80/tcp myapache
7b14efe89074 httpd "httpd-foreground" 6 minutes ago Up 6 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp apache
[root@192 ~]
<html><body><h1>my apache\!</h1></body></html>
[root@192 ~]
<html><body><h1>my apache\!</h1></body></html>
七、卷技术
简介
前面我们说了docker是为了使用者能将代码和运行环境一起打包到一个隔离的docker容器中运行,docker容器产生的数据如果不通过commit或者save保存的话,那当我们把docker容器删除后里面的数据也就跟着删除了。为了能够保存数据,于是在docker中引入的卷。 卷是某个文件或者目录,它不同于联合文件系统,它是独立存在的,可以在/var/lib/docker/volumes下查看。 卷设计的目的就是实现数据的持久化,当容器被删除后不会删除其挂载的数据卷
简单实战
[root@192 /]
[root@192 /]
baa270f07163d1539f98dad1af4af282d78734689d5d3a42548d1ce7e51b7ab3
[root@192 /]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
baa270f07163 httpd "httpd-foreground" 4 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp apache
[root@192 /]
[root@192 www]
[root@192 www]
[root@192 www]
<html>
<head>test</head>
<body><h1>hhhh</h1></body>
</html>
[root@192 www]
<html>
<head>test</head>
<body><h1>hhhh</h1></body>
</html>
[root@192 www]
/docker/apache/www
[root@192 www]
root@baa270f07163:/usr/local/apache2
root@baa270f07163:/usr/local/apache2/htdocs
index.html
root@baa270f07163:/usr/local/apache2/htdocs
<html>
<head>test</head>
<body><h1>hhhh</h1></body>
</html>
root@baa270f07163:/usr/local/apache2/htdocs
八、DockerFile
简介
我们现在可以从dockerhub或者阿里云等镜像站拉取镜像然后运行,但是那些都是别人提交的镜像,在我们自己使用时有些地方还是不太不方便。我们就可以通过DockerFile来自定义一个镜像。DockerFile由多条指令构成,经过编译后就可以生成一个自定义镜像。
- DockerFile里面每个关键字都约定大写
- DockerFile指令从上到下依次执行
- DockerFile每条指令都会创建一个镜像层,能写一行的都写一行
- #表示注释
指令介绍
FROM [image[:tag/digest]]
- 指定基础镜像,并且必须是第一条指令
- 如果不以任何镜像为基础则写为FROM scratch
MAINTAINER <name> (已被LABEL替代)
LABEL<key>=<value> [<key>=<value> …]
ADD (<src>…) <des>
- 把宿主机上的文件复制到镜像中
- src为压缩包则自动解压,也可为url
- dest路径可为绝对路径也可以是相对工作目录的相对路径
COPY(<src>…) <des>
EXPOSE
ENV<key>=<value> [<key>=<value> …]
RUN <Command>/[“executable”,“param1”,“param2”]
CMD [“param1”,“param2”]/[“executable”,“param1”,“param2”]/Command param1 param2
- 设置容器在启动时默认执行的命令
- 上面用双引号的地方不能用单引号
ENTRYPOINT [“executable”,“param1”,“param2”]/Command param1 param2
WORKDIR
VOLUME [“path”,[…]]/path …
ONBUILD
九、Docker网络
Docker网络详解
我们启动Docker服务时,系统就会新建一个Docker0虚拟网桥,就像一个虚拟的交换机,它的一端连通了物理或者虚拟网卡,另一端连接容器。这样就能让容器和主机连上了同一个物理网口,在主机上使用ifconfig可以看到。
每当我们运行一个容器的时候docker就会使用evth-pair技术给容器分配一个IP。在主机上创建一对虚拟网卡veth-pair设备,它总是成对出现的,因此常用来连接两个网络设备。一端命名为eth0并放在新创建的容器中,另一端命名为veth并连接上docker0网桥上,通过ip addr查看容器的IP发现默认都是docker0在同一个网段。
这样我们就可以在容器里面ping通物理机 整个网络的拓扑图为
Doceker 网络互联
试想我们在实际生产环境中IP地址一般都是会任意更换的,我们可不可以通过服务器名连接呢,我们可以通过ping来试一下。
发现我们通过容器名来是ping不通的,那我们怎么解决这个问题呢? 我们可以在创建容器时通过–link来联通两个容器,这样就可以实现通过容器名互联了。 发现刚刚的问题似乎解决了,但我们如果用centos来ping centos3发现还是不行。 其实–link的本质是通过修改了centos3的hosts文件实现的 我们如果要实现通过容器名访问centos的话,只要在centos的hosts文件下也加上centos3的地址,那除了这种方法还有没有其他更好的方法呢?
Docker自定义网络
我们上面使用的都是系统创建的网络,docker还给我们提供了自己创建网络的方法。 docker network docker的网络相关操作
ls 列出所有网络
rm 删除一个或多个网络
create 创建网络
connect 将一个容器与网络连接
disconnect 断开容器与网络的连接
inspect 展示网络的详细信息
prune 移除所有未使用的网络
查看系统当前的网络
[root@laptop-670cig77 ~]
NETWORK ID NAME DRIVER SCOPE
579ee165f9ea bridge bridge local
3e9bbcf9bd15 host host local
c150b24024cc none null local
我们也可以通过docker network create 自定义新的网络
docker network create
--driver 网络连接方式(默认为bridge)
--gateway 设置网关
--subnet 设置子网
eg:
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
现在回到上面的问题---->怎么才能通过容器名实现容器之间的通信
- docker1.10开始,内嵌了一个DNS server。
- DNS解析功能必须在自定义网络中使用。
- 启动容器时使用 --name 参数指定容器名称。
于是我们现在可以通过自定义网络来更方便的解决这个问题
Docker网路连通
在真实生产中不仅有多个容器也可能有多个网络,那我们两个网络下的两个容器之间是否可以联通呢? 结果发现是无法ping通的 我们可以通过docker network connect 将mynet1和centos1联通即可 联通后centos1即可ping通centos1,在centos1内也将新建一个网卡指向mynet1 同时mynet2中也会分配一个ip给centos1 参考资料 https://www.bilibili.com/video/BV1og4y1q7M4 https://haicoder.net/docker/docker-course.html https://blog.csdn.net/runner668/article/details/93137765 https://blog.csdn.net/qq_43371556/article/details/102631158 https://segmentfault.com/a/1190000015684472 https://blog.csdn.net/AtlanSI/article/details/87892016
|