为什么要学习 docker 呢?深有体会,由于一些原因只能在他人电脑上搭建环境,明明在自己电脑上的程序跑的好好的,在他人的电脑上就是死活出错。折磨人呀!!!!!可是能怎么办,工作还得继续,曲线救国呗,折腾了一天终于搞好了,那么以后呢?想到了之前搭建靶机时候用到的docker,时间长了也忘了,准备好好梳理学习入门一波。《十分感谢大神的文章,本文基于大神的文章学习整理。》
一、入门基础
Docker 使用 Google 公司推出的 Go 语言进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
热衷于 Ubuntu,后面的所有操作都是基于 Ubuntu的。
1. 基本概念
Docker的三大组件:镜像、容器、仓库
1.1 镜像
操作系统分为内核和用户空间,内核启动后会挂在root文件系统为用户控件提供支撑。
Docker镜像就相当于一个root文件系统,但它是一个特殊的文件系统。提供了
(1)容器运行时所需的程序、库、资源、配置等文件,
(2)为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。
1.2 容器
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,容器进程运行于属于自己的命名空间。容器可以拥有自己的root文件系统、网络配置、进程空间、自己的用户ID空间,是在一个隔离的环境里。
1.3 仓库
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。
<仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy。
仓库服务分类为:
Docker Registry 公开服务
私有 Docker Registry
2. Ubuntu安装Docker服务
# 将apt源使用https以确保软件下载过程中不被篡改,添加使用HTTPS传输的软件包以及CA证书
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
# 为确保下载软件包的合法性,需要添加软件源的GPG秘钥
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# 向 source.list 中添加 Docker软件源
sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"
# 更新Ubuntu源
sudo apt-get update
# 安装 Docker CE
sudo apt-get install docker-ce
# 使用脚本自动安装
curl -fsSL get.docker.com -o get-docker.sh
# 可以国内源进行安装
sudo sh get-docker.sh --mirror Aliyun
# 启动 Docker CE
sudo systemctl enable docker
sudo systemctl start docker
# 建立 docker 用户组
sudo groupadd docker
# 将当前用户加入到 docker组中
sudo usermod -aG docker $USER
# 关闭当前Terminal重新连接Ubuntu
# 测试Docker是否安装正确,执行命令,看到下面的输出就说明正确安装了
docker run hello-word
# 卸载旧版本的docker
sudo apt-get remove docker docker-engine docker.io
二、Docker使用
1. 镜像操作
1.1 获取镜像
从下载过程中,我们可以看到docker的镜像是由多层存储所构成的,下载也是一层层的下载,下载过程中给出了没一层的ID的前12位,并且下载结束后,给出该镜像完整的sha256的摘要,以确保下载一致性。
# 获取镜像格式
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
# 查看docker获取镜像帮助
docker pull --help
# 例如
docker pull ubuntu:18.04
# jenkins的下载过程
docker pull jenkins
Using default tag: latest
latest: Pulling from library/jenkins
55cbf04beb70: Pulling fs layer
55cbf04beb70: Downloading [=========> ] 8.289MB/45.31MB
9a8ea045c926: Pulling fs layer
d4eee24d4dac: Downloading [============> ] 12.71MB/50.06MB
c58988e753d7: Pulling fs layer
d4eee24d4dac: Downloading [==========> ] 10.68MB/50.06MB
70fcfa476f73: Download complete
0539c80a02be: Downloading 6.405MB
54fefc6dcf80: Waiting
911bc90e47a8: Waiting
38430d93efed: Waiting
7e46ccda148a: Waiting
c0cbcb5ac747: Waiting
35ade7a86a8e: Waiting
aa433a6a56b1: Waiting
841c1dd38d62: Waiting
b865dcb08714: Waiting
5a3779030005: Waiting
12b47c68955c: Waiting
1322ea3e7bfd: Waiting
# 下载安装完就会出现下面输出信息
Digest: sha256:eeb4850eb65f2d92500e421b430ed1ec58a7ac909e91f518926e02473904f668
Status: Downloaded newer image for jenkins:latest
docker.io/library/jenkins:latest
docker run的相关参数解释:
# docker启动Jenkins服务
sudo docker run -d -p 8099:8080 -v /opt/data/jenkins_home:/var/jenkins_home --name wjenkins jenkins:latest
docker run -it --rm ubuntu:18.04 bash
-it: -i,交互式操作;t,终端;
-rm:容器退出后随之将其删除,避免浪费空间
-d:是后台启用jenkins服务
-p:端口映射
--name:为容器命名
ubuntu:18.04:指用 ubuntu:18.04 镜像为基础来启动容器
bash:放在镜像后的是命令,可以创造一个交互式的shell
-v:挂载数据 /opt/data/jenkins_home:/var/jenkins_home 映射 jenkins_home到本地/opt/data/jenkins_home目录。例如启动jenkins的初始密码,秘钥库等都从这里面找
1.2 查看镜像
# 查看docker中全部的镜像
docker images
# 查看docker中部分的镜像
docker image ls jenkins
REPOSITORY(仓库名) TAG(版本) IMAGE ID(镜像ID) CREATED(创建时间) SIZE(所占用空间)
jenkins latest cd14cecfdb3a 17 months ago 696MB
# 镜像体积
# 查看镜像、容器、数据卷所占用的空间
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 1 695.7MB 695.7MB (99%)
Containers 2 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
# 虚悬镜像(dangling image)--- 目前没看到,也没看到有什么用
# 查看虚悬镜像
docker image ls -f dangling=true
# 删除虚悬镜像
docker image prune
# 中间层镜像(为了加速镜像构建、重复利用资源,Docker 会利用 中间层镜像。所以在使用一段时间后,可能会看到一些依赖的中间层镜像)
docker image ls -a
# 以特定格式显示
docker image ls --format "{{.ID}}: {{.Repository}}"
fce289e99eb9: hello-world
cd14cecfdb3a: jenkins
# 以表格等距显示,并且有标题行
docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
IMAGE ID REPOSITORY TAG
fce289e99eb9 hello-world latest
cd14cecfdb3a jenkins latest
docker image ls 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。
1.3 删除镜像
# 删除镜像格式
docker image rm [选项] <镜像1> [<镜像2> ...]
# docker中存在的镜像
docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest fce289e99eb9 12 months ago 1.84kB
jenkins latest cd14cecfdb3a 17 months ago 696MB
# 长ID删除
docker image rm fce289e99eb9
# 短ID删除,一般去长ID的前三位就能区分镜像
docker image rm fce
# 通过镜像名删除镜像
docker image rm hello-world
# 查看镜像摘要
docker image ls --digests
# 通过镜像摘要删除镜像
docker image rm node@sha256:4fe721ccc2e8dc7362278a29dc660d833570ec2682f4e4194f4ee23e415e1064
# docker image ls 命令来配合删除
docker image rm $(docker image ls -q redis)
2. 容器操作
容器是独立运行的一个或一组应用,以及他们的运行态环境。
2.1 启动
启动容器的两种方式:
1.基于镜像新建一个容器并启动:docker run,该命令的标准操作
(1)检查本地是否存在指定的镜像,不存在就从公有仓库下载
(2)利用镜像创建并启动一个容器
(3)分配一个文件系统,并在制度的镜像层外爱你挂载一层可读写层
(4)从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
(5)从地址池配置一个IP地址给容器
(6)执行用户指定的应用程序
(7)执行完毕后容器被终止
2.在终止状态的容器重启启动:docker container start
# 新建并启动
# 用ubuntu输出打印
docker run ubuntu:18.04 /bin/echo "Hello Ubuntu"
# 启动一个bash终端,允许用户交互
docker run -t -i ubuntu /bin/bash
# 启动已终止容器
docker container start [容器的名称NAMES]
2.2 守护态进行
大多数是需要让docker在后台运行而不是直接把执行命令的结果输出在当前宿主机下。通过-d参数来实现。
# 不加-d参数运行容器,容器回吧输出的结果(STDOUT)打印到宿主机上
docker run ubuntu /bin/sh -c "while true; do echo hello world; sleep 1;done;"
hello world
hello world
hello world
...
# 加-d参数在后台运行
docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1;done;"
014d585a42f3974814e8d00d3be17b0babeda887456c8539e1922bc5d749368f
# 查看容器的信息docker container ls
docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
014d585a42f3 ubuntu "/bin/sh -c 'while t…" 52 seconds ago Up 47 seconds zealous_gauss
# 查看容器后台打印的日志信息docker container logs [docker container -d后的那个ID]
docker container logs 014d585a42f3974814e8d00d3be17b0babeda887456c8539e1922bc5d749368f
hello world
hello world
hello world
...
2.3 终止
# 查看容器的运行状态
docker container ls -a
# 终止一个运行中的容器
docker container stop [ID]
# 启动一个容器
docker container start [容器的名称NAMES]
# 重新启动一个容器
docker container restart [容器的名称NAMES]
2.4 进入容器
使用-d参数,容器启动后会进入后台。那么怎么进入容器操作呢?
docker attch [ID或ID的前三位:docker container ls出的]
exit 退出的时候回导致容器停止
docker exec(推荐使用)
-i -t: 可以使用熟悉的 Linux命令提示符
exit 退出的时候不会使容器退出
# 后台交互式启动ubuntu
docker run -dit ubuntu
5f7cbebeb2b97f8ac8de6a8b79e196dcd7583a37435781ef6669e9237ad9f39d
# 查看容器的运行
docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5f7cbebeb2b9 ubuntu "/bin/bash" 39 seconds ago Up 34 seconds hopeful_spence
# docker exec 进入容器
docker exec -it 5f7 bash
root@5f7cbebeb2b9:/#
# docker attach J进入容器
docker attach 57f bash
2.5 导出和导入
# 导出容器 docker export
docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5f7cbebeb2b9 ubuntu "/bin/bash" 3 minutes ago Up 3 minutes hopeful_spence
docker export 5f7cbebeb2b9 > ubuntu.tar
# 导入容器快照docker import
cat ubuntu.tar | docker import - test/ubuntu:v1.0
sha256:e27783b11623f2f56137ab8469963296d14545aac6607febe5e7d4c83a92c6f3
# 通过执行的URL或者某个目录来导入
docker import http://example.com/exampleimage.tgz example/imagerepo
# 查看导入的容器
docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
test/ubuntu v1.0 e27783b11623 10 seconds ago 64.2MB
2.6 删除
# 删除容器 docker container rm [容器的名字:通过docker contaniner ls 可以查看]
ubuntu@VM-0-8-ubuntu:~$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5f7cbebeb2b9 ubuntu "/bin/bash" 9 minutes ago Up 9 minutes hopeful_spence
ubuntu@VM-0-8-ubuntu:~$ docker container rm hopeful_spence
Error response from daemon: You cannot remove a running container 5f7cbebeb2b97f8ac8de6a8b79e196dcd7583a37435781ef6669e9237ad9f39d. Stop the container before attempting removal or force remove
ubuntu@VM-0-8-ubuntu:~$ docker container stop hopeful_spence
hopeful_spence
ubuntu@VM-0-8-ubuntu:~$ docker container rm hopeful_spence
hopeful_spence
# 清理所有处于终止状态的容器 docker container prune
# 用 docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器
ubuntu@VM-0-8-ubuntu:~$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
014d585a42f3 ubuntu "/bin/sh -c 'while t…" About an hour ago Exited (0) 17 minutes ago zealous_gauss
28ceff128046 ubuntu "/bin/sh -c 'while t…" About an hour ago Exited (0) About an hour ago cocky_bohr
9ae9bef2e2d5 ubuntu "/bin/bash" About an hour ago Exited (0) About an hour ago trusting_tereshkova
978423cea835 ubuntu "/bin/echo 'Hello Ub…" 2 hours ago Exited (0) 2 hours ago angry_bose
0a73192e9dfd hello-world "/hello" 2 hours ago Exited (0) 2 hours ago eloquent_wilbur
81f60b6062e3 hello-world "/hello" 26 hours ago Exited (0) 26 hours ago elegant_almeida
d9d4d77cbf25 hello-world "/hello" 2 days ago Exited (0) 2 days ago condescending_easley
ubuntu@VM-0-8-ubuntu:~$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
014d585a42f3974814e8d00d3be17b0babeda887456c8539e1922bc5d749368f
28ceff12804603c73d3516654b0b915a909053268529855e234d58ca7567663b
9ae9bef2e2d56680a2056a7853fee9b87eb90186db9ff44823030f3266faf0b6
978423cea83542f1120f8c27451107c2a00df48becbc2e99a62da977acd899f9
0a73192e9dfdd6f4969cf50286fcd3bc36a6e00f2a14822d73dd85f62749c616
81f60b6062e394ab3dc3e6e560e17522472a84cccf768865f88652b02af4a7d4
d9d4d77cbf258ffcb2bf5d6375284bd303517bc3c5e69c60a17a29592023d439
Total reclaimed space: 12B
ubuntu@VM-0-8-ubuntu:~$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3.访问仓库
仓库是集中存放镜像的地方。
3.1 Docker Hub
1.注册官方的docker账号:https://hub.docker.com
2.登录docker login; 退出docker logout
3.拉取镜像:docker search ubuntu
4.拉取镜像:docker pull ubuntu
5.推送镜像:docker push 自己的镜像
docker tag ubuntu:18.04 username/ubuntu:18.04
docker image ls
docker push username/ubuntu:18.04
docker search username
3.2 私有仓库
docker-register是官方提供的工具,可以用于构建私有的镜像仓库。
# 获取官方register镜像来运行
docker run -d -p 5000:5000 --restart=always --name registry registry
# 启动私有仓库
# -v参数来将镜像文件存在本地的指定路径
docker run -d -p 5000:5000 -v /opt/data/registry:/var/lib/registry registry
# 然后和共有仓的操作就一样了
# 但是Registry 创建的仓库面临一些维护问题。比如某些镜像删除以后空间默认是不会回收的,需要一些命令去回收空间然后重启 Registry 程序。Nexus可以很好解决这个问题
# 启动 Nexus 容器
# 第一次启动 Nexus 的默认帐号是 admin 密码是 admin123 登录以后点击页面上方的齿轮按钮进行设置
docker run -d --name nexus3 --restart=always \
-p 8081:8081 \
--mount src=nexus-data,target=/nexus-data \
sonatype/nexus3
4.数据管理
在容器中管理数据主要有两种方式:
数据卷
挂在主机目录
4.1 数据卷
4.2 挂在主机目录
5.使用网络
Docker允许通过外部访问容器或容器互联的方式提供网络服务。
5.1 外部访问容器
通过 -P 或 -p 参数来指定端口映射,Docker会随机映射一个49000~49900的端口到内部容器开放的网络端口。
docker run -d -p tranining/webapp python app.py
# 查看容器的端口映射
docker container ls -l
# 查看应用信息
docker logs -f nostalgic_morse
# 映射所有接口地址(使用 hostPort:containerPort 格式本地的 5000 端口映射到容器的 5000 端口)
docker run -d -p 5000:5000 training/webapp python app.py
# 映射到指定地址的指定接口(可以使用 ip:hostPort:containerPort 格式指定映射使用一个特定地址)
docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
# 映射到指定地址的任意端口(使用 ip::containerPort 绑定 localhost 的任意端口到容器的 5000 端口,本地主机会自动分配一个端口)
docker run -d -p 127.0.0.1::5000 training/webapp python app.py
# 查看映射端口配置
docker port nostalgic_morse[容器名称] 5000
5.2 容器互联
强烈建议将容器加入自定义的Docker网络开连接多个容器
# 新建网络my-net
docker run -it --rm --name busybox1 --network my-net busybox sh
# 运行容器并加入到my-net网络中
docker run -it --rm --name busybox2 --network my-net busybox sh
# 查看容器信息
docker container ls
# ping 来证明 busybox1 容器和 busybox2 容器建立了互联关系,分别在容器中去ping对方
5.3 配置DNS
6. Kubernetes
Kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。
听过一个演讲课,目前行业中流行的是K8S+Docker架构。
7.靶机搭建(Docker实战)
【学习转载pageuo的FreeBuf.com文章】,谢谢大佬的分享。
项目实际中为了验证扫描器的扫描准确性和扫描器的性能,由于长期扫描国外开源的扫描靶机会被封禁IP,影响扫描结果。为了项目的可持续性,想到了自己来搭建靶场验证扫描器的功能和性能。感谢pageuo大佬的靶机搭建经验。
7.1 搭建Vulhub
Vulhub是由 Phithon 维护的一款面向大众的开源漏洞靶场,只需要根据命令编译、运行就可搭建一个完整的漏洞靶场镜像。
# 配置docker基础环境
# 安装pip
curl -shttps://bootstrap.pypa.io/get-pip.py | python3
# 安装docker
sudo apt-get update && apt-get install docker.io
# 启动docker服务
sudo service docker start
# 安装compose
pip install docker-compose
# 拉取编译运行靶机
# 拉取vulhub
git clone git@github.com:phith0n/vulhub.git
# 在线编译docker环境
cd vulhub/struts/s2-016
docker-compose build
# 启动靶机
docker-compose up -d
7.2 搭建Vulapp
Vulapp手机各种漏洞环境,统一采用Dockerfile进行管理,同事也手机了安全工具环境。
# 拉取Vulapp
git clone git@github.com:Medicean/VulApps.git