㈠ 清除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 就可以成功地將一個宿主機上的目錄或文件,不動聲色地掛載到容器中。