0x01 安装
docker镜像搜索:https://hub.docker.com/r/aflp...
1、安装docker:国内 daocloud 一键安装命令:curl -sSL https://get.daocloud.io/docker | sh
2、通过禅道官网进行docker镜像的安装
https://www.zentao.net/book/z...
docker常用命令
docker search xxx //从镜像仓库中搜索xxx镜像
docker image ls //查看所有docker镜像
docker network ls //查看容器网路
docker ps //查看当前所有运行中的容器 -a 查看所有容器
docker ps -l //查看最近创建的一个容器
docker ps -n x //查看最近创建的x个容器
docker exec -it [container id] bash
docker cp 202010281439113.sql.php zentao:/www/zentaopms/tmp/backup/ //将本机文件上传到docker
docker image pull <repository>:<tag> //从仓库拉取镜像
docker stop 容器id 停止容器
docker rm 容器id 删除容器
docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
docker ps --no-trunc 查看容器完整commands信息
docker ps -a|grep 镜像名|awk '{print $1}'|xargs docker rm //删除镜像名为xxx的容器
docker build -t sniffer-web:v3.0 . 创建容器镜像
查看docker挂载在本机的位置
已运行的容器修改配置 var/lib/docker/containers/[hash_of_the_container]/hostconfig.json
其中的hashofthecontainer是docker镜像的hash值,修改完需要重启容器
已知docker地址,pull镜像
https://hub.docker.com/r/zjuc...
docker pull zjuchenyuan/angora
docker run后停止了容器怎么再重新打开
docker start -ia [容器id]
把用户加到docker组,不使用使用sudo docker
//将登陆用户加入到docker用户组中
sudo gpasswd -a $USER docker
//更新用户组
newgrp docker
//测试docker命令是否可以使用sudo正常使用
sudo service docker restart
docker ps
0x02 docker参数
-rm
在Docker容器退出时,默认容器内部的文件系统仍然被保留,以方便调试并保留用户数据。
但是,对于foreground容器,由于其只是在开发调试过程中短期运行,其用户数据并无保留的必要,因而可以在容器启动时设置--rm选项,这样在容器退出时就能够自动清理容器内部的文件系统。示例如下:
docker run --rm bba-208
等价于
docker run --rm=true bba-208
显然,--rm选项不能与-d同时使用,即只能自动清理foreground容器,不能自动清理detached容器
注意,--rm选项也会清理容器的匿名data volumes。
所以,执行docker run命令带--rm命令选项,等价于在容器退出后,执行docker rm -v- --name="容器新名字": 为容器指定一个名称;
- -d: 后台运行容器,并返回容器ID,也即启动守护式容器;
- -i:以交互模式运行容器,通常与 -t 同时使用;
- -t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-P: 随机端口映射;
-p: 指定端口映射,有以下四种格式
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort- -w, --workdir string 指定工作目录
privileged被引入docker。
使用该参数,container内的root拥有真正的root权限。
否则,container内的root只是外部的一个普通用户权限。
privileged启动的容器,可以看到很多host上的设备,并且可以执行mount。甚至允许你在docker容器中启动docker容器。- sh -c "make clean;make"
--env CC=afl-clang-fast 执行docker run的时候添加环境变量
*0x03 问题解决
/var/lib/docker 目录过大 https://www.hangge.com/blog/c...
Docker修改已有镜像,并打包生成新的镜像tar文件
https://blog.csdn.net/u014412...
0x04 深入学习
容器原理
一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。这也是容器技术中一个非常重要的概念,即:容器是一个“单进程”模型。由于一个容器的本质就是一个进程,用户的应用进程实际上就是容器里 PID=1 的进程,也是其他后续创建的所有进程的父进程。这就意味着,在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程。但是,在后面分享容器设计模式时,我还会推荐其他更好的解决办法。这是因为容器本身的设计,就是希望容器和应用能够同生命周期,这个概念对后续的容器编排非常重要。否则,一旦出现类似于“容器是正常运行的,但是里面的应用早已经挂了”的情况,编排系统处理起来就非常麻烦了。另外,跟 Namespace 的情况类似,Cgroups 对资源的限制能力也有很多不完善的地方,被提及最多的自然是 /proc 文件系统的问题。众所周知,Linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。但是,你如果在容器里执行 top 指令,就会发现,它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据。造成这个问题的原因就是,/proc 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,即:/proc 文件系统不了解 Cgroups 限制的存在。在生产环境中,这个问题必须进行修正,否则应用程序在容器里读取到的 CPU 核数、可用内存等信息都是宿主机上的数据,这会给应用的运行带来非常大的困惑和风险。这也是在企业中,容器化应用碰到的一个常见问题,也是容器相较于虚拟机另一个不尽如人意的地方。
对 Docker 项目来说,它最核心的原理实际上就是为待创建的用户进程:启用 Linux Namespace 配置;设置指定的 Cgroups 参数;切换进程的根目录(Change Root)。- Dockerfile
# 使用官方提供的Python开发镜像作为基础镜像
FROM python:2.7-slim
# 将工作目录切换为/app
WORKDIR /app
# 将当前目录下的所有内容复制到/app下
ADD . /app
# 使用pip命令安装这个应用所需要的依赖
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# 允许外界访问容器的80端口
EXPOSE 80
# 设置环境变量
ENV NAME World
# 设置容器进程为:python app.py,即:这个Python应用的启动命令
CMD ["python", "app.py"]
容器网络
docker容器默认使用bridge模式
可以用 –net 选项指定容器的网络模式。host模式 : 使用 –net=host 指定。与宿主机共享网络,此时容器没有使用网络的namespace,宿主机的所有设备,如Dbus会暴露到容器中,因此存在安全隐患。
container模式 : 使用 –net=container:NAME_or_ID 指定。指定与某个容器实例共享网络。
none模式 : 使用 –net=none 指定。不设置网络,相当于容器内没有配置网卡,用户可以手动配置。
bridge模式 : 使用 –net=bridge 指定,默认设置。此时docker引擎会创建一个veth对,一端连接到容器实例并命名为eth0,另一端连接到指定的网桥中(比如docker0),因此同在一个主机的容器实例由于连接在同一个网桥中,它们能够互相通信。容器创建时还会自动创建一条SNAT规则,用于容器与外部通信时。如果用户使用了-p或者-Pe端口端口,还会创建对应的端口映射规则。
自定义模式 : 使用自定义网络,可以使用docker network create创建,并且默认支持多种网络驱动,用户可以自由创建桥接网络或者overlay网络。
默认是桥接模式,网络地址为172.17.0.0/16,同一主机的容器实例能够通信,但不能跨主机通信。容器间通信
Docker容器间的通信方式根据媒介可以分为:volume共享通信(挂载卷 -v)、网络通信(--network)等
1、网络通信docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过“容器名”通信。方法很简单,只要在启动时用 --name 为容器命名就可以了。
下面启动两个容器 bbox1 和 bbox2:
docker run -it --network=my_net2 --name=bbox1 busybox
docker run -it --network=my_net2 --name=bbox2 busybox
然后,bbox2 就可以直接 ping 到 bbox1 了:
使用 docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的。- k8s之间的通信
https://network.51cto.com/art...
https://testerhome.com/articl...
0x05 k8s
yaml文件:
现在已经制作好了一个 Nginx 容器镜像,希望让平台帮我启动这个镜像。并且,要求平台帮我运行两个完全相同的 Nginx 副本,以负载均衡的方式共同对外提供服务。
需要做的则是编写如下这样一个 YAML 文件(比如名叫 nginx-deployment.yaml)apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
在上面这个 YAML 文件中,我们定义了一个 Deployment 对象,它的主体部分(spec.template 部分)是一个使用 Nginx 镜像的 Pod,而这个 Pod 的副本数是 2(replicas=2)。
然后执行:$ kubectl create -f nginx-deployment.yaml
这样,两个完全相同的 Nginx 容器副本就被启动了。k8s集群部署
目标: 在所有节点上安装 Docker 和 kubeadm;部署 Kubernetes Master;部署容器网络插件;部署 Kubernetes Worker;部署 Dashboard 可视化插件;
#在安装 kubeadm 的过程中,kubeadm 和 kubelet、kubectl、kubernetes-cni 这几个二进制文件都会被自动安装好。
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
$ cat <<EOF > /etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
$ apt-get update
$ apt-get install -y docker.io kubeadm
1、部署 Kubernetes 的 Master 节点
这里编写了一个给 kubeadm 用的 YAML 文件(名叫:kubeadm.yaml):
apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
controllerManagerExtraArgs:
horizontal-pod-autoscaler-use-rest-clients: "true"
horizontal-pod-autoscaler-sync-period: "10s"
node-monitor-grace-period: "10s"
apiServerExtraArgs:
runtime-config: "api/all=true"
kubernetesVersion: "stable-1.11"
这个配置中,我给 kube-controller-manager 设置了:
horizontal-pod-autoscaler-use-rest-clients: "true"
这意味着,将来部署的 kube-controller-manager 能够使用自定义资源(Custom Metrics)进行自动水平扩展。这是我后面文章中会重点介绍的一个内容。
其中,“stable-1.11”就是 kubeadm 帮我们部署的 Kubernetes 版本号,即:Kubernetes release 1.11 最新的稳定版,在我的环境下,它是 v1.11.1。你也可以直接指定这个版本,比如:kubernetesVersion: “v1.11.1”。
然后,我们只需要执行一句指令:
$ kubeadm init --config kubeadm.yaml就可以完成 Kubernetes Master 的部署了,这个过程只需要几分钟。部署完成后,kubeadm 会生成一行指令:
kubeadm join 10.168.0.2:6443 --token 00bwbx.uvnaa2ewjflwu1ry --discovery-token-ca-cert-hash sha256:00eb62a2a6020f94132e3fe1ab721349bbcd3e9b94da9654cfe15f2985ebd711
这个 kubeadm join 命令,就是用来给这个 Master 节点添加更多工作节点(Worker)的命令。我们在后面部署 Worker 节点的时候马上会用到它,所以找一个地方把这条命令记录下来。
此外,kubeadm 还会提示我们第一次使用 Kubernetes 集群所需要的配置命令:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
而需要这些配置命令的原因是:Kubernetes 集群默认需要加密方式访问。所以,这几条命令,就是将刚刚部署生成的 Kubernetes 集群的安全配置文件,保存到当前用户的.kube 目录下,kubectl 默认会使用这个目录下的授权信息访问 Kubernetes 集群。
如果不这么做的话,我们每次都需要通过 export KUBECONFIG 环境变量告诉 kubectl 这个安全配置文件的位置。
现在,我们就可以使用 kubectl get 命令来查看当前唯一一个节点的状态了:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady master 1d v1.11.1
可以看到,这个 get 指令输出的结果里,Master 节点的状态是 NotReady,这是为什么呢?
在调试 Kubernetes 集群时,最重要的手段就是用 kubectl describe 来查看这个节点(Node)对象的详细信息、状态和事件(Event),我们来试一下:
$ kubectl describe node master
...Conditions:...Ready False ... Kubelet
通过 kubectl describe 指令的输出,我们可以看到 NodeNotReady 的原因在于,我们尚未部署任何网络插件。
另外,我们还可以通过 kubectl 检查这个节点上各个系统 Pod 的状态,其中,kube-system 是 Kubernetes 项目预留的系统 Pod 的工作空间(Namepsace,注意它并不是 Linux Namespace,它只是 Kubernetes 划分不同工作空间的单位):
$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-78fcdf6894-j9s52 0/1 Pending 0 1h
coredns-78fcdf6894-jm4wf 0/1 Pending 0 1h
etcd-master 1/1 Running 0 2s
kube-apiserver-master 1/1 Running 0 1s
kube-controller-manager-master 0/1 Pending 0 1s
kube-proxy-xbd47 1/1 NodeLost 0 1h
kube-scheduler-master 1/1 Running 0 1s
可以看到,CoreDNS、kube-controller-manager 等依赖于网络的 Pod 都处于 Pending 状态,即调度失败。这当然是符合预期的:因为这个 Master 节点的网络尚未就绪。
二、部署网络插件
在 Kubernetes 项目“一切皆容器”的设计理念指导下,部署网络插件非常简单,只需要执行一句 kubectl apply 指令,以 Weave 为例:
$ kubectl apply -f https://git.io/weave-kube-1.6
部署完成后,我们可以通过 kubectl get 重新检查 Pod 的状态:
$ kubectl get pods -n kube-system
可以看到,所有的系统 Pod 都成功启动了,而刚刚部署的 Weave 网络插件则在 kube-system 下面新建了一个名叫 weave-net-cmk27 的 Pod,一般来说,这些 Pod 就是容器网络插件在每个节点上的控制组件。
Kubernetes 支持容器网络插件,使用的是一个名叫 CNI 的通用接口,它也是当前容器网络的事实标准,市面上的所有容器网络开源项目都可以通过 CNI 接入 Kubernetes,比如 Flannel、Calico、Canal、Romana 等等,它们的部署方式也都是类似的“一键部署”。关于这些开源项目的实现细节和差异,我会在后续的网络部分详细介绍。
至此,Kubernetes 的 Master 节点就部署完成了。如果你只需要一个单节点的 Kubernetes,现在你就可以使用了。不过,在默认情况下,Kubernetes 的 Master 节点是不能运行用户 Pod 的,所以还需要额外做一个小操作。在本篇的最后部分,我会介绍到它。
部署 Kubernetes 的 Worker 节点Kubernetes 的 Worker 节点跟 Master 节点几乎是相同的,它们运行着的都是一个 kubelet 组件。唯一的区别在于,在 kubeadm init 的过程中,kubelet 启动后,Master 节点上还会自动运行 kube-apiserver、kube-scheduler、kube-controller-manger 这三个系统 Pod。
所以,相比之下,部署 Worker 节点反而是最简单的,只需要两步即可完成。
第一步,在所有 Worker 节点上执行“安装 kubeadm 和 Docker”一节的所有步骤。
第二步,执行部署 Master 节点时生成的 kubeadm join 指令:
$ kubeadm join 10.168.0.2:6443 --token 00bwbx.uvnaa2ewjflwu1ry --discovery-token-ca-cert-hash sha256:00eb62a2a6020f94132e3fe1ab721349bbcd3e9b94da9654cfe15f2985ebd711
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。