㈠ 清除k8s中node节点无用的镜像
1、使用kubectl get po –namespace 命名空间,查看该命名空间已有的pod
2、重新部署pod,在该node节点上产生多余的images镜像
3、使用春陪docker system df命令,在执行清除镜像之前先查看镜像和容器的数量。
注:类似于Linux上的df命令,用于查看Docker的磁盘使用情况。这条命令可以查看到node节点中镜像和容器的数量
4、使用docker system prune –a。清除无用的镜像
注:docker system prune命令可裤竖以用于清理磁盘,删除关闭的容器、无用的数据卷和网络,以及dangling镜像(即无tag的镜像)。docker system prune -a命令清理得更加彻底,可以将没有容器使用Docker镜像都删掉。注意,这两个命令会把你暂时关闭的容器,以及暂时没有用到的Docker镜像都删掉了…所以使用之前一定胡森大要想清楚呐。
5、使用docker system df令,查看镜像和容器的数量;是否成功
㈡ k8s编写yaml拉取镜像
https://kubernetes.io/zh/docs/tasks/configure-pod-container/assign-memory-resource/
要查看 metrics-server 或资源指标 API (metrics.k8s.io) 是否已经运行,请运行以下命令
kubectl get apiservices
创建一个命名空间,以便将本练习中创建的资源与集群的其余部分隔离。
kubectl create namespace mem-example
查看fluent-bit的yaml
fluent-bit的yaml文件是
查看yaml
kubectl get FluentBit -n kubesphere-logging-system -o yaml
编写fb-test的测试yaml
参考 https://www.jianshu.com/p/35dde2b1951b
建立一个yaml,yaml从dockerhub上拉下来镜像
运行
kubectl apply -f fb-test.yaml --namespace=fb-test
查看pods
kubectl get pods -n fb-test
kubectl describe pod fb-test-pod -n fb-test
查看docker进程
docker ps
打银戚印docker日志看是不是在生产
docker logs -f 36b0e26bc8c7
停掉
docker stop 36b0e26bc8c7
注意,昨天我以为锋含陵停止docker就会导致pod重启老告,结果pod有自启了docker
kubectl delete pods/fb-test-pod -n fb-test
㈢ 03 CenterOS7.9 安装K8s过程
防火墙等禁用
将桥接的IPv4流量传递到iptables的链
NTP时间同步
配置国内k8s镜像地址
k8s镜像仓库需要翻出去,所以配置国内镜像地址
安装K8s(安装和使能kubelet)
配置cgroupdriver=systemd
默认docker的Cgroup是cgroups,kubelet的Cgroups是systemd,两者的Cgroups不一样,两边需要修改成一致的配置
然后依据提示执行:
然后重新初始化
然后检查健康状况:
上面kubectl get cs结果显示系统不健康,解决方案如下:
把下面文件的 - --port=0注释掉,即前面加上#
修改kube-flannel.yml里面为(vi中使用:set number,然后 :106定位到106行):
2、高可用测试
接下来我们分别尝试删除pod和停止Container来测试高可用性:
修改内容为:
用firefox浏览器访问:访问https://192.168.2.130:30001
一共有3个Master:
master:192.168.108.88 k8s-master03
backup:192.168.108.87 k8s-master02
backup:192.168.108.86 k8s-master04
二个worker节点:
k8s-node1:192.168.100.49
k8s-node2:192.168.100.50
各个master把自己公钥州凳伍发到同册或一个master上汇总(这里选用k8s-master01),然后分发到各个master上:
接下来把汇总的公钥分发给其他master主粗和机(k8s-master02和k8s-master03):
到各个master上修改文件访问权限:
各个master节点依据自己情况做少量更改,主要是:
1、自己的被选举权重
2、自己的网卡名称
在本例中,主master节点配置(/etc/keepalived/keepalived.conf)为:
第一个备份master节点配置(/etc/keepalived/keepalived.conf):
第二个备份master节点配置为(/etc/keepalived/keepalived.conf):
仿造前面做node和master的配置(master到初始化master的前一步)这里略去,参考前面即可
鉴于我们是在非master高可用基础上做的高可用,即原来的master上曾经执行过kubeadm init,所以这里需要在这个节点上先执行reset操作(只需要在原来的那一个master节点上执行即可)
在MASTER上建一个脚本然后执行:
在所有其他的BACKUP master上建一个脚本然后执行:
㈣ k8s-乱七八糟
2020.5.29
1、k8s:
1、namespace:命名空间,(群组)
2、service: 服务、暴露pod、网关代理
3、pod: 容器 最小单元 # docker中最小单元容器,一个pod可存放多个容器
Master组件主要包括:
kube-apiserver:负责对外暴露Kubernetes API;
etcd:用于存储Kubernetes集群的所有数据;
kube-scheler: 负责为新创建的Pod选择可供其运行的节点;
kube-controller-manager: 包含Node Controller,Deployment Controller,Endpoint Controller等等,通过与apiserver交互使相应的资源达到预期状态伏仔咐。
Node组件主要包括:
kubelet:负责维护和管理节点上Pod的运行状态;
kube-proxy:负责维护主机上的网络规则以及转发。
Container Runtime:如Docker,rkt,runc等提供容器运行时环境。
k8s默认会从远端拉取镜像,其配置参数imagePullPolicy为Always。所以,如果yaml文件中没有定义那就是使用默认的,因此我们可以通过将该参数显示设置为Never或者IfNotPresent,k8s就会从本地拉取镜像了
——————
service4中类型:
1、ClusterIP类型:这个service有一个Cluster-IP,其实就一个VIP。具体实现原理依靠kube-proxy组件,通过iptables或是ipvs实现。这种类型的service 只能在集群内访问----kubectl get svc -n test 查看
2、NodePort 类型:配置services后可通过node节点的相应端口访问到内部pod。该端口有一定的范围,比如默认Kubernetes 控制平面将在--service-node-port-range标志指定的范围内分配端口(默认值:30000-32767)
3、ExternalName 类型service将服务映射到 DNS 名称,而不是典型的选择器,例如my-service或者cassandra。您可以使用spec.externalName参数指定这些服务。---Externalip 端口对外映射没有限制
4、LoadBalancer类型的service 是可以实缺纯现集群外部访问服务的另外一种解决方案。不过并不是所有的k8s集群都会支持,大多是在公有云托管集群中会支持该类型。负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过Service的status.loadBalancer字段被发布出去。
原文链接:https://blog.csdn.net/weixin_40274679/article/details/107887678
1、 k8s 调整容器配置
两个方法:1、通过配置yaml文件,去调度pod生效。yaml文件修改和重新调度会使pod重新关闭后重新创建
2、通过scale(缩放--缩小或放大)命令直接调度,增加一个pod:kubectl scale --replicas=个数 kind类型/pod名称/ -n 命名空间
配置镜像命令:
kubectl set image deployment <deploymentName> <containerName>=<image> -n namespace
kubectl set image deployment/hello-world hello-world=registry.gag.cn/business/hello-world:20200728-03 -n test
k8s查看所有pod详细信息
kubectl get pod --all-namespaces -o wide
获取部署pod-deployment和删除,可删除多个pod
kubectl get deployments
戚数 kubectl delete deployments pod名 -n namespace
kubectl delete pod pod名 --grace-period=0 --force
1、跨namespace和svc通讯需要加namespace空间名 svc.ns
2、k8s插件
flannel :使用比较广泛的、简单的、不需要用户干预,从k8s跟进一起出
calico:网络的安全和规则上比flannel要好,更灵活的控制网络,且如果需要------有付费维护服务
canal:以上两种的结合品,实际并没有什么优势。。。
Weave:更加丰富的网络功能
3、
㈤ k8s 基本使用(上)
本文将介绍 k8s 中的一些最基本的命令,并辅以解释一些基本概念来方便理解,也就是说,本文是一篇偏向实用性而非学术性的文章,如果你想提前了解一下 k8s 相关的知识的话,可以通过以下链接进行学习:
k8s 是经典的一对多模型,有一个主要的管理节点 master 和许多的工作节点 slaver 。当然,k8s 也可以配置多个管理节点,拥有两个以上的管理节点被称为 高可用 。k8s 包括了许多的组件,每个组件都是单运行在一个 docker 容器中,然后通过自己规划的虚拟网络相互访问。你可以通过 kubectl get pod -n kube-system 查看所有节点上的组件容器。
在管理节点中会比工作节点运行更多的 k8s 组件,我们就是靠着这些多出来的组件来对工作节点发号施令。他们都叫什么这里就不详细提了。反正对于”基本使用“来说,这些名字并不重要。
要想理解一个东西就要先明白它的内在理念。通俗点就是,k8s 做了什么?为了提供更加可靠的服务,就要增加服务器的数量,减少每个服务器的体量来平摊负载,而越来越多的虚拟机就会带来越来越高的运维成本。如何让少量的运维人员就可以管理数量众多的服务器及其上的服务呢?这就是 k8s 做的工作。
k8s 把数量众多的服务器重新抽象为一个统一的资源池 ,对于运维人员来说,他们面前没有服务器1、服务器2的概念,而是一个统一的资源池,增加新的服务器对运维人员来说,只是增加自资源池的可用量。不仅如此,k8s 把所有能用的东西都抽象成了资源的概念,从而提供了一套更统一,更简洁的管理方式。
接下来,我会把每个基本命令当做一节来进行介绍,并辅以介绍一些基本概念。本文介绍的命令涵盖了增删改查四方面,可参加下面表格,因为篇幅较长,我们将 create 及之后的不那么常用的命令放在下一篇文章 k8s 基本使用(下) 里讲:
接下来进入正题,首先来了解一下 k8s 中最最最常用的命令 kubectl get ,要记住,k8s 把所有的东西都抽象成了资源,而 kubectl get 就是用来查看这些资源的。最常见的资源就是 pod 。
不仅我们自己的服务是要包装成 pod 的,就连 k8s 自己也是运行在一堆 pod 上。接下来就让我们查看一下 k8s 的 pod :
-n 参数指定了要查看哪个命名空间下的 pod 。 k8s 所有的 pod 都被放置在 kube-system 命名空间下。
执行了 kubectl get pod -n kube-system 命令后,你就可以看到如下内容:
其中每一行就是一个资源,这里我们看到的资源是 pod 。你看到的 pod 数量可能和我的不一致,因为这个列表里包含了 k8s 在所有节点上运行的 pod ,你加入的节点越多,那么显示的 pod 也就越多。我们来一列一列的看:
kubectl get 可以列出 k8s 中所有资源
这里只介绍了如何用 kubectl 获取 pod 的列表。但是不要把 get 和 pod 绑定在一起,pod 只是 k8s 中的一种服务,你不仅可以 get pod ,还可以 get svc ( 查看服务 )、 get rs ( 查看副本控制器 )、 get deploy ( 查看部署 )等等等等,虽然说 kubectl get pod 是最常用的一个,但是如果想查看某个资源而又不知道命令是什么, kbuectl get <资源名> 就对了。
如果你想看更多的信息,就可以指定 -o wide 参数,如下:
加上这个参数之后就可以看到资源的所在 ip 和所在节点 node 了。
记得加上 -n
-n 可以说是 kubectl get 命令使用最频繁的参数了,在正式使用中,我们永远不会把资源发布在默认命名空间。所以,永远不要忘记在 get 命令后面加上 -n 。
kubectl get 命令可以列出 k8s 中的资源,而 kubectl get pod 是非常常用的查看 pod 的命令。而 -n 参数则可以指定 pod 所在的命名空间。
kubectl describe 命令可以用来查看某一资源的具体信息,他同样可以查看所有资源的详情, 不过最常用的还是查看 pod 的详情 。他也同样可以使用 -n 参数指定资源所在的命名空间。
举个例子,我们可以用下面命令来查看刚才 pod 列表中的某个 pod,注意不要忘记把 pod 名称修改成自己的:
然后你就可以看到很多的信息,咱们分开说,首先是基本属性,你可以在详细信息的开头找到它:
基本属性
其中几个比较常用的,例如 Node 、 labels 和 Controlled By 。通过 Node 你可以快速定位到 pod 所处的机器,从而检查该机器是否出现问题或宕机等。通过 labels 你可以检索到该 pod 的大致用途及定位。而通过 Controlled By ,你可以知道该 pod 是由那种 k8s 资源创建的,然后就可以使用 kubectl get <资源名> 来继续查找问题。例如上文 DaemonSet/kube-flannel-ds-amd64 ,就可以通过 kubectl get DaemonSet -n kube-system 来获取上一节资源的信息。
内部镜像信息
在中间部分你可以找到像下面一样的 Containers 段落。该段落详细的描述了 pod 中每个 docker 容器的信息,常用的比如 Image 字段,当 pod 出现 ImagePullBackOff 错误的时候就可以查看该字段确认拉取的什么镜像。其他的字段名都很通俗,直接翻译即可。
事件
在 describe 查看详情的时候,最常用的信息获取处就是这个 Event 段落了,你可以在介绍内容的末尾找到它,如下:
是的,如果你看到上面这样,没有任何 Events 的话,就说明该 pod 一切正常。当 pod 的状态不是 Running 时,这里一定会有或多或少的问题,长得像下面一样,然后你就可以通过其中的信息分析 pod 出现问题的详细原因了:
kubectl describe <资源名> <实例名> 可以查看一个资源的详细信息,最常用的还是比如 kubectl describe pod <pod名> -n <命名空间> 来获取一个 pod 的基本信息。如果出现问题的话,可以在获取到的信息的末尾看到 Event 段落,其中记录着导致 pod 故障的原因。
如果你想查看一个 pod 的具体日志,就可以通过 kubectl logs <pod名> 来查看。注意,这个只能查看 pod 的日志。通过添加 -f 参数可以持续查看日志。例如,查看 kube-system 命名空间中某个 flannel pod 的日志,注意修改 pod 名称:
然后就可以看到如下输出:
如果你发现某个 pod 的服务有问题,但是状态还是显示 Running ,就可以使用 kubectl logs 来查看其详细日志。
在本篇文章里,我们了解了 k8s 的宗旨和一些基本概念,并知道了最为常用的 get 、 descibe 及 logs 命令,知道了这三条命令之后就几乎可以从 k8s 中获取所有常用信息了。接下来的 k8s 基本使用(下) 里,我们会更深一步,来了解 k8s 中如何创建、修改及删除资源。
㈥ k8s是怎么启动镜像的
k8s可通过以下方式进行汪郑启动镜像:
1、建议进入相机--点击右上角的“...”图标--在屏幕下方左滑,将镜像开关打开;
2、还可以进入相机--点击右上角的困慎颂设置按钮--开启自拍镜像。
百倍用心,10分满意孝毁
㈦ k8s-私有云镜像库使用
k8s集群环境安装完毕,创建pod时报错repository does not exist or may require 'docker login',node节点已经登录过docker镜像库、胡伍可以正裤册或常拉取镜像,k8s调度就不行!
私有镜像库需姿旅要添加 imagePullSecrets:---其实就是给k8s创建一个连接私有镜像库的地址、账号、密码
pod-yaml文件中加入参数
imagePullSecrets:
- name: 名字
参考文章
https://blog.csdn.net/qq_37377136/article/details/104880304?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%%7Edefault-1.control
㈧ skywalking—docker镜像构建k8s部署
前言
skywalking是个非常不错的apm产帆闭品,但是在使用过程中有个非常蛋疼的问题,在基于es的存储情况下,es的数据一有问题,就会导致整个skywalking web ui服务不可用,然后需要agent端一个服务一个服亏汪务的停用,然后服务重新部署后好,全部走一遍。这种问题同样也会存在skywalking的版本升级迭代中。而且apm 这种过程数据是允许丢弃的,默认skywalking中关于trace的数据记录只保存了90分钟。故博主准备将skywalking的部署容器化,一键部署升级。下文是整个skywalking 容器化部署的过程。
目标:将skywalking的docker镜像运行在k8s的集群环境中提供服务
docker镜像构建
FROMregistry.cn-xx.xx.com/keking/jdk:1.8ADDapache-skywalking-apm-incubating/ /opt/apache-skywalking-apm-incubating/RUNln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo 'Asia/Shanghai' >/etc/timezone \
&& chmod +x /opt/apache-skywalking-apm-incubating/config/setApplicationEnv.sh \
&& chmod +x /opt/apache-skywalking-apm-incubating/webapp/setWebAppEnv.sh \
&& chmod +x /opt/apache-skywalking-apm-incubating/bin/startup.sh \
&& echo "tail -fn 100 /opt/apache-skywalking-apm-incubating/logs/webapp.log" >> /opt/apache-skywalking-apm-incubating/bin/startup.shEXPOSE8080 10800 11800 12800CMD/opt/apache-skywalking-apm-incubating/态空裂config/setApplicationEnv.sh \
&& sh /opt/apache-skywalking-apm-incubating/webapp/setWebAppEnv.sh \
&& /opt/apache-skywalking-apm-incubating/bin/startup.sh
在编写Dockerfile时需要考虑几个问题:skywalking中哪些配置需要动态配置(运行时设置)?怎么保证进程一直运行(skywalking 的startup.sh和tomcat中 的startup.sh类似)?
application.yml
#cluster:# zookeeper:# hostPort: localhost:2181# sessionTimeout: 100000naming:jetty:#OS real network IP(binding required), for agent to find collector clusterhost:0.0.0.0port:10800contextPath:/cache:# guava:caffeine:remote:gRPC:# OS real network IP(binding required), for collector nodes communicate with each other in cluster. collectorN --(gRPC) --> collectorMhost:#real_hostport:11800agent_gRPC:gRPC:#os real network ip(binding required), for agent to uplink data(trace/metrics) to collector. agent--(grpc)--> collectorhost:#real_hostport:11800# Set these two setting to open ssl#sslCertChainFile: $path#sslPrivateKeyFile: $path# Set your own token to active auth#authentication: xxxxxxagent_jetty:jetty:# OS real network IP(binding required), for agent to uplink data(trace/metrics) to collector through HTTP. agent--(HTTP)--> collector# SkyWalking native java/.Net/node.js agents don't use this.# Open this for other implementor.host:0.0.0.0port:12800contextPath:/analysis_register:default:analysis_jvm:default:analysis_segment_parser:default:bufferFilePath:../buffer/bufferOffsetMaxFileSize:10MbufferSegmentMaxFileSize::trueui:jetty:# Stay in `localhost` if UI starts up in default mode.# Change it to OS real network IP(binding required), if deploy collector in different machine.host:0.0.0.0port:12800contextPath:/storage:elasticsearch:clusterName:#elasticsearch_:trueclusterNodes:#elasticsearch_clusterNodesindexShardsNumber:2indexReplicasNumber:0highPerformanceMode:true# Batch process setting, refer to https://www.elastic.co/guide/en/elasticsearch/client/java-api/5.5/java-docs-bulk-processor.htmlbulkActions:2000# Execute the bulk every 2000 requestsbulkSize:20# flush the bulk every 20mbflushInterval:10# flush the bulk every 10 seconds whatever the number of requestsconcurrentRequests:2# the number of concurrent requests# Set a timeout on metric data. After the timeout has expired, the metric data will automatically be deleted.traceDataTTL:2880# Unit is minuteminuteMetricDataTTL:90# Unit is minutehourMetricDataTTL:36# Unit is hourdayMetricDataTTL:45# Unit is daymonthMetricDataTTL:18# Unit is month#storage:# h2:# url: jdbc:h2:~/memorydb# userName: saconfiguration:default:#namespace: xxxxx# alarm :2000serviceErrorRateThreshold:10.::10.::10.:2000# ::40# max collection's size of worker cache collection, setting it smaller when collector OutOfMemory crashed.workerCacheMaxSize:10000#receiver_zipkin:# default:# host: localhost# port: 9411# contextPath: /
webapp.yml
动态配置:密码,grpc等需要绑定主机的ip都需要运行时设置,这里我们在启动skywalking的startup.sh只之前,先执行了两个设置配置的脚本,通过k8s在运行时设置的环境变量来替换需要动态配置的参数
setApplicationEnv.sh
#!/usr/bin/env shsed -i"s/#elasticsearch_clusterNodes/${elasticsearch_clusterNodes}/g"/opt/apache-skywalking-apm-incubating/config/application.ymlsed -i"s/#elasticsearch_clusterName/${elasticsearch_clusterName}/g"/opt/apache-skywalking-apm-incubating/config/application.ymlsed -i"s/#real_host/${real_host}/g"/opt/apache-skywalking-apm-incubating/config/application.yml
setWebAppEnv.sh
#!/usr/bin/env shsed -i"s/#skywalking_password/${skywalking_password}/g"/opt/apache-skywalking-apm-incubating/webapp/webapp.ymlsed -i"s/#real_host/${real_host}/g"/opt/apache-skywalking-apm-incubating/webapp/webapp.yml
保持进程存在:通过在skywalking 启动脚本startup.sh末尾追加"tail -fn 100
/opt/apache-skywalking-apm-incubating/logs/webapp.log",来让进程保持运行,并不断输出webapp.log的日志
Kubernetes中部署
apiVersion:extensions/v1beta1kind:Deploymentmetadata:name:skywalkingnamespace:uatspec:replicas:1selector:matchLabels:app:skywalkingtemplate:metadata:labels:app:skywalkingspec:imagePullSecrets:-name:registry-pull-secretnodeSelector:apm:skywalkingcontainers:-name:skywalkingimage:registry.cn-xx.xx.com/keking/kk-skywalking:5.2imagePullPolicy:Alwaysenv:-name:elasticsearch_clusterNamevalue:elasticsearch-name:elasticsearch_clusterNodesvalue:172.16.16.129:31300-name:skywalking_passwordvalue:xxx-name:real_hostvalueFrom:fieldRef:fieldPath:status.podIPresources:limits:cpu:1000mmemory:4Girequests:cpu:700mmemory:2Gi---apiVersion:v1kind:Servicemetadata:name:skywalkingnamespace:uatlabels:app:skywalkingspec:selector:app:skywalkingports:-name:web-aport:8080targetPort:8080nodePort:31180-name:web-bport:10800targetPort:10800nodePort:31181-name:web-cport:11800targetPort:11800nodePort:31182-name:web-dport:12800targetPort:12800nodePort:31183type:NodePort
Kubernetes部署脚本中唯一需要注意的就是env中关于pod ip的获取,skywalking中有几个ip必须绑定容器的真实ip,这个地方可以通过环境变量设置到容器里面去
结语
整个skywalking容器化部署从测试到可用大概耗时1天,其中花了个多小时整了下谭兄的skywalking-docker镜像(
https://hub.docker.com/r/wutang/skywalking-docker/),发现有个脚本有权限问题(谭兄反馈已解决,还没来的及测试),以及有几个地方自己不是很好控制,便build了自己的docker镜像,其中最大的问题还是解决集群中网络通讯的问题,一开始我把skywalking中的服务ip都设置为0.0.0.0,然后通过集群的nodePort映射出来,这个时候的agent通过集群ip+31181是可以访问到naming服务的,然后通过naming服务获取到的collector gRPC服务缺变成了0.0.0.0:11800, 这个地址agent肯定访问不到collector的,后面通过绑定pod ip的方式解决了这个问题。
㈨ Docker&k8s(一)
容器技术的核心功能,就是通过约束和修改进程的动态表现,从而为其创造出一个“边界” 。对于 Docker 等大多数 Linux 容器来说, Cgroups 技术 是用来制造早派约陆游贺束的主要手段,而 Namespace 技术 则是用来修改进程视图的主要方法。
其实只是 Linux 创建新进程的一个可选参数。我们知道,在 Linux 系统中创建线程的系统调用是 clone(),比如:
这个系统调用就会为我们创建一个新的进程,并且返回它的进程号 pid。而当我们用 clone() 系统调用创建一个新进程时,就可以在参数中指定 CLONE_NEWPID 参数,比如:
这时,新创建的这个进程将会“看到”一个全新的进程空间,在这个进程空间里,它的 PID 是 1。之所以说“看到”,是因为这只是一个“障眼法”,在宿主机真实的进程空间里,这个进程的 PID 还是真实的数值,比如 100。
而 除了 PID Namespace,Linux 操作系统还提供了 Mount、UTS、IPC、Network 和 User 这些 Namespace,用来对各种不同的进程上下文进行“障眼法”操作。
比如,Mount Namespace,用于让被隔离进程只看到当前 Namespace 里的挂载点信息;Network Namespace,用于让被隔离进程看到当前 Namespace 里的网络设备和配置。
这,就是 Linux 容器最基本的实现原理了。所以说,容器,其实是一种特殊的进程而已。Namespace 技术实际上修改了应用进程看待整个计算机“视图”,即它的“视线”被操作系统做了限制,只能“看到”某些指定的内容 。
优势:更加的轻量且没有损耗资源。弊端:隔离不彻底
Cgroups(Linux Control Group) 就是 Linux 内核中用来为进程设置资源限制的一个重要功能。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等
Cgroups 给用户暴露出来的操作接口是文件系统
比如,向 container 组里的 cfs_quota 文件写入 20 ms(20000 us):
意味着在每 100 ms 的时间里,被该控制组限制的进程只能使用 20 ms 的 CPU 时间,也就是说这个进程只能使用到 20% 的 CPU 带宽。
把被限制的进程的 PID 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了:
除 CPU 子系统外,Cgroups 的每一项子系统都有其独有的资源限制能力,比如:
Linux Cgroups 的设计还是比较易用的,简单粗暴地理解呢,它就是一个子系统目录加上一组资源限制文件的组合。容器是一个“单进程”模型。
Mount Namespace 修改的,是容器进程对文件系统“挂载点”的认知。Mount Namespace 跟其他 Namespace 的使用略有不同的地方:它对容器进程视图的改变,一定是伴随着挂载操作(mount)才能生效。实际上,Mount Namespace 正是基于对 chroot 的不断改良才被发明出来的,它也是 Linux 操作系统里的第一个 Namespace。
而这个挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,叫作:rootfs(根文磨肢件系统)。
对 Docker 项目来说,它最核心的原理实际上就是为待创建的用户进程:
rootfs 只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在 Linux 操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像。
容器的 rootfs 由如下图所示的三部分组成:
第一部分,只读层 :它是这个容器的 rootfs 最下面的五层,对应的正是 ubuntu:latest 镜像的五层,挂载方式都是只读的(ro+wh,即 readonly+whiteout)
这些层,都以增量的方式分别包含了 Ubuntu 操作系统的一部分
第二部分,可读写层。 (rw)
在没有写入文件之前,这个目录是空的。而一旦在容器里做了写操作,你修改产生的内容就会以增量的方式出现在这个层中。如果要删除AuFS 会在可读写层创建一个 whiteout 文件,把只读层里的文件“遮挡”起来。
专门用来存放你修改 rootfs 后产生的增量,原先的只读层里的内容则不会有任何变化
第三部分,Init 层。
有些文件本来属于只读的 Ubuntu 镜像的一部分,但是用户往往需要在启动容器时写入一些指定的值比如 hostname,所以就需要在可读写层对它们进行修改。可是,这些修改往往只对当前的容器有效,我们并不希望执行 docker commit 时,把这些信息连同可读写层一起提交掉。所以,Docker 做法是,在修改了这些文件之后,以一个单独的层挂载了出来。而用户执行 docker commit 只会提交可读写层,所以是不包含这些内容的。可以参考git ignore的思想。
Dockerfile :
ENTRYPOINT:entrypoint才是正统地用于定义容器启动以后的执行体的,其实我们从名字也可以理解,这个是容器的“入口”。
CMD:cmd给出的是一个容器的默认的可执行体。也就是容器启动以后,默认的执行的命令。如果docker run没有指定任何的执行命令或者dockerfile里面也没有entrypoint,那么,就会使用cmd指定的默认的执行命令执行如果你不额外指定,那么就执行cmd的命令,否则呢?只要你指定了,那么就不会执行cmd,也就是cmd会被覆盖。
docker commit,实际上就是在容器运行起来后,把最上层的“可读写层”,加上原先容器镜像的只读层,打包组成了一个新的镜像。当然,下面这些只读层在宿主机上是共享的,不会占用额外的空间。
而由于使用了联合文件系统,你在容器里对镜像 rootfs 所做的任何修改,都会被操作系统先复制到这个可读写层,然后再修改。这就是所谓的:Copy-on-Write。
一个进程的每种 Linux Namespace,都在它对应的 /proc/[进程号]/ns 下有一个对应的虚拟文件,并且链接到一个真实的 Namespace 文件上。
这也就意味着:一个进程,可以选择加入到某个进程已有的 Namespace 当中,从而达到“进入”这个进程所在容器的目的,这正是 docker exec 的实现原理。
Volume 机制,允许你将宿主机上指定的目录或者文件,挂载到容器里面进行读取和修改操作。
当容器进程被创建之后,尽管开启了 Mount Namespace,但是在它执行 chroot(或者 pivot_root)之前,容器进程一直可以看到宿主机上的整个文件系统。所以在 rootfs 准备好之后,在执行 chroot 之前,把 Volume 指定的宿主机目录(比如 /home 目录),挂载到指定的容器目录(比如 /test 目录)在宿主机上对应的目录(即 /var/lib/docker/aufs/mnt/[可读写层 ID]/test)上,这个 Volume 的挂载工作就完成了。
由于执行这个挂载操作时,“容器进程”已经创建了,也就意味着此时 Mount Namespace 已经开启了。所以,这个挂载事件只在这个容器里可见。你在宿主机上,是看不见容器内部的这个挂载点的。这就 保证了容器的隔离性不会被 Volume 打破 。
而这里要使用到的挂载技术,就是 Linux 的 绑定挂载(bind mount)机制 。它的主要作用就是,允许你将一个目录或者文件,而不是整个设备,挂载到一个指定的目录上。并且,这时你在该挂载点上进行的任何操作,只是发生在被挂载的目录或者文件上,而原挂载点的内容则会被隐藏起来且不受影响。绑定挂载实际上是一个 inode 替换的过程。在 Linux 操作系统中,inode 可以理解为存放文件内容的“对象”,而 dentry,也叫目录项,就是访问这个 inode 所使用的“指针”。
所以,在一个正确的时机,进行一次绑定挂载,Docker 就可以成功地将一个宿主机上的目录或文件,不动声色地挂载到容器中。