容器的本質是一種特殊的進程。html
在linux容器中有三個重要的概念:Namespace、Cgroups、rootfs。前端
Namespace作隔離,讓進程只能看到Namespace中的世界;node
Cgroups 作限制,讓這個「世界」圍着一個看不見的牆。mysql
rootfs 作文件系統,rootfs 只是一個操做系統所包含的文件、配置和目錄,並不包括操做系統內核。linux
這樣就實現了進程在咱們所看到的一個與世隔絕的房間,這個房間就是Pass項目賴以生存的"沙盒"。nginx
進入容器後,ps命令看到的容器的應用進程都是1號進程,這個實際上是pid namespace致使,他其實就是個障眼法,git
讓你看到的是相似於一個新的虛擬機新環境,實際上是不同的,容器就是一個運行的進程,而容器中的其餘進程則是pid爲1的子進程。web
除了剛剛pid namespace,還有其它的namespace以下:redis
容器是怎麼新建namespace的?算法
docker建立容器,其實就是linux系統的一次fork的調用,
在進行fork調用時,會傳入一些flag參數,這個參數能夠控制對linux內核調用新的namespace。
掛載在容器根目錄上、用來爲容器進程提供隔離後執行環境的文件系統,就是所謂的「容器鏡像」。它還有一個更爲專業的名字,叫做:rootfs(根文件系統)。
容器的rootfs由三部分組成,1:只讀層、2:可讀寫層、3:init層
1.只讀層:都以增量的方式分別包含了 操做系統的一部分。
2.可讀寫:就是專門用來存放你修改 rootfs 後產生的增量,不管是增、刪、改,都發生在這裏。而當咱們使用完了這個被修改過的容器以後,還可使用 docker commit 和 push 指令,保存這個被修改過的可讀寫層,並上傳到 Docker Hub 上,供其餘人使用;而與此同時,原先的只讀層裏的內容則不會有任何變化。這,就是增量 rootfs 的好處。
3.Init 層:是 Docker 項目單獨生成的一個內部層,專門用來存放 /etc/hosts、/etc/resolv.conf 等信息。
service是k8s中的一個重要概念,主要是提供負載均衡和服務自動發現。
Service 是由 kube-proxy 組件,加上 iptables 來共同實現的。
建立Service的方法有兩種:
1.經過kubectl expose建立
#kubectl expose deployment nginx --port=88 --type=NodePort --target-port=80 --name=nginx-service 這一步說是將服務暴露出去,其實是在服務前面加一個負載均衡,由於pod可能分佈在不一樣的結點上。 –port:暴露出去的端口 –type=NodePort:使用結點+端口方式訪問服務 –target-port:容器的端口 –name:建立service指定的名稱
2.經過yaml文件建立
建立一個名爲hostnames-yaohong的服務,將在端口80接收請求並將連接路由到具備標籤選擇器是app=hostnames的pod的9376端口上。
使用kubectl creat來建立serivice
apiVersion: v1 kind: Service metadata: name: hostnames-yaohong spec: selector: app: hostnames ports: - name: default protocol: TCP port: 80 //該服務的可用端口 targetPort: 9376 //具備app=hostnames標籤的pod都屬於該服務
使用以下命令來檢查服務:
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.187.0.1 <none> 443/TCP 18d
使用kubectl exec 命令來遠程執行容器中命令
$ kubectl -n kube-system exec coredns-7b8dbb87dd-pb9hk -- ls / bin coredns dev etc home lib media mnt proc root run sbin srv sys tmp usr var
雙橫槓(--)表明kubectl命令項的結束,在雙橫槓後面的內容是指pod內部須要執行的命令。
服務並非和pod直接相連的,介於他們之間的就是Endpoint資源。
Endpoint資源就是暴露一個服務的IP地址和端口列表。
經過service查看endpoint方法以下:
$ kubectl -n kube-system get svc kube-dns NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterI P 10.187.0.2 <none> 53/UDP,53/TCP 19d $ kubectl -n kube-system describe svc kube-dns Name: kube-dns Namespace: kube-system Labels: addonmanager.kubernetes.io/mode=Reconcile k8s-app=kube-dns kubernetes.io/cluster-service=true kubernetes.io/name=CoreDNS Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"prometheus.io/scrape":"true"},"labels":{"addonmanager.kubernetes.io/mode":... prometheus.io/scrape: true Selector: k8s-app=kube-dns Type: ClusterIP IP: 10.187.0.2 Port: dns 53/UDP TargetPort: 53/UDP Endpoints: 10.186.0.2:53,10.186.0.3:53 //表明服務endpoint的pod的ip和端口列表 Port: dns-tcp 53/TCP TargetPort: 53/TCP Endpoints: 10.186.0.2:53,10.186.0.3:53 Session Affinity: None Events: <none>
直接查看endpoint信息方法以下:
#kubectl -n kube-system get endpoints kube-dns NAME ENDPOINTS AGE kube-dns 10.186.0.2:53,10.186.0.3:53,10.186.0.2:53 + 1 more... 19d #kubectl -n kube-system describe endpoints kube-dns Name: kube-dns Namespace: kube-system Labels: addonmanager.kubernetes.io/mode=Reconcile k8s-app=kube-dns kubernetes.io/cluster-service=true kubernetes.io/name=CoreDNS Annotations: <none> Subsets: Addresses: 10.186.0.2,10.186.0.3 NotReadyAddresses: <none> Ports: Name Port Protocol ---- ---- -------- dns 53 UDP dns-tcp 53 TCP Events: <none>
若是建立pod時不包含選擇器,則k8s將不會建立endpoint資源。這樣就須要建立endpoint來指的服務的對應的endpoint列表。
service中建立endpoint資源,其中一個做用就是用於service知道包含哪些pod。
除了手動配置來訪問外部服務外,還可使用徹底限定域名(FQDN)訪問外部服務。
apiVersion: v1 kind: Service metadata: name: Service-yaohong spec: type: ExternalName //代碼的type被設置成了ExternalName
externalName: someapi.somecompany.com // 實際服務的徹底限定域名(FQDN)
port: - port: 80
服務建立完成後,pod能夠經過external-service.default.svc.cluster.local域名(甚至是external-service)鏈接外部服務。
有3種方式在外部訪問服務:
1.將服務的類型設置成NodePort;
2.將服務的類型設置成LoadBalance;
3.建立一個Ingress資源。
NodePort 服務是引導外部流量到你的服務的最原始方式。NodePort,正如這個名字所示,在全部節點(虛擬機)上開放一個特定端口,任何發送到該端口的流量都被轉發到對應服務。
YAML 文件相似以下:
apiVersion: v1 kind: Service metadata: name: Service-yaohong spec: type: NodePort //爲NodePort設置服務類型 ports: - port: 80 targetPort: 8080 nodeport: 30123 //經過集羣節點的30123端口能夠訪問服務 selector: app: yh
這種方法有許多缺點:
1.每一個端口只能是一種服務
2.端口範圍只能是 30000-32767
若是節點/VM 的 IP 地址發生變化,你須要能處理這種狀況
基於以上緣由,我不建議在生產環境上用這種方式暴露服務。若是你運行的服務不要求一直可用,或者對成本比較敏感,你可使用這種方法。這樣的應用的最佳例子是 demo 應用,或者某些臨時應用。
LoadBalancer 服務是暴露服務到 internet 的標準方式。在 GKE 上,這種方式會啓動一個 Network Load Balancer[2],它將給你一個單獨的 IP 地址,轉發全部流量到你的服務。
經過以下方法來定義服務使用負載均衡
apiVersion: v1 kind: Service metadata: name: loadBalancer-yaohong spec: type: LoadBalancer //該服務從k8s集羣的基礎架構獲取負載均衡器 ports: - port: 80 targetPort: 8080 selector: app: yh
什麼時候使用這種方式?
若是你想要直接暴露服務,這就是默認方式。全部通往你指定的端口的流量都會被轉發到對應的服務。它沒有過濾條件,沒有路由等。這意味着你幾乎能夠發送任何種類的流量到該服務,像 HTTP,TCP,UDP,Websocket,gRPC 或其它任意種類。
這個方式的最大缺點是每個用 LoadBalancer 暴露的服務都會有它本身的 IP 地址,每一個用到的 LoadBalancer 都須要付費,這將是很是昂貴的。
爲何使用Ingress,一個重要的緣由是LoadBalancer服務都須要建立本身的負載均衡器,以及獨有的公有Ip地址,而Ingress只須要一個公網Ip就能爲許多服務提供訪問。
Ingress 事實上不是一種服務類型。相反,它處於多個服務的前端,扮演着「智能路由」或者集羣入口的角色。
你能夠用 Ingress 來作許多不一樣的事情,各類不一樣類型的 Ingress 控制器也有不一樣的能力。
編寫以下ingress.yml文件
kind: Ingress metadata: name: ingressyaohong spec: rules: - host: kubia.example.com http: paths: - path: / backend: serviceName: kubia-nodeport servicePort: 80
經過以下命令進行查看ingress
# kubectl create -f ingress.yml
經過kubectl get ing命令進行查看ingress
# kubectl get ing NAME HOSTS ADDRESS PORTS AGE ingressyaohong kubia.example.com 80 2m
瞭解Ingress的工做原理
什麼時候使用這種方式?
Ingress 多是暴露服務的最強大方式,但同時也是最複雜的。Ingress 控制器有各類類型,包括 Google Cloud Load Balancer, Nginx,Contour,Istio,等等。它還有各類插件,好比 cert-manager[5],它能夠爲你的服務自動提供 SSL 證書。
若是你想要使用同一個 IP 暴露多個服務,這些服務都是使用相同的七層協議(典型如 HTTP),那麼Ingress 就是最有用的。若是你使用本地的 GCP 集成,你只須要爲一個負載均衡器付費,且因爲 Ingress是「智能」的,你還能夠獲取各類開箱即用的特性(好比 SSL、認證、路由等等)。
1.將不一樣的服務映射到相同的主機不一樣的路徑
apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: rules: - host: kubia.example.com http: paths: - path: /yh //對kubia.example.com/yh請求轉發至kubai服務 backend: serviceName: kubia servicePort:80 - path: /foo //對kubia.example.com/foo請求轉發至bar服務 backend: serviceName: bar servicePort:80
2.將不一樣的服務映射到不一樣的主機上
apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: rules: - host: yh.example.com http: paths: - path: / //對yh.example.com請求轉發至kubai服務 backend: serviceName: kubia servicePort:80 - host: bar.example.com http: paths: - path: / //對bar.example.com請求轉發至bar服務 backend: serviceName: bar servicePort:80
客戶端和控制器之間的通訊是加密的,而控制器和後端pod之間的通訊則不是。
apiVersion: v1 kind: Ingress metadata: name: Ingress-yaohong spec: tls: //在這個屬性中包含全部的TLS配置 - hosts: - yh.example.com //將接收來自yh.example.com的TLS鏈接 serviceName: tls-secret //從tls-secret中得到以前創立的私鑰和證書 rules: - host: yh.example.com http: paths: - path: / //對yh.example.com請求轉發至kubai服務 backend: serviceName: kubia servicePort:80
就緒探針有三種類型:
1.Exec探針,執行進程的地方。容器的狀態由進程的退出狀態代碼肯定。
2.HTTP GET探針,向容器發送HTTP GET請求,經過響應http狀態碼判斷容器是否準備好。
3.TCP socket探針,它打開一個TCP鏈接到容器的指定端口,若是鏈接創建,則認爲容器已經準備就緒。
啓動容器時,k8s設置了一個等待時間,等待時間後纔會執行一次準備就緒檢查。以後就會週期性的進行調用探針,並根據就緒探針的結果採起行動。
若是某個pod未就緒成功,則會從該服務中刪除該pod,若是pod再次就緒成功,則重新添加pod。
與存活探針區別:
就緒探針若是容器未準備就緒,則不會終止或者重啓啓動。
存活探針經過殺死異常容器,並用新的正常的容器來替代他保證pod正常工做。
就緒探針只有準備好處理請求pod纔會接收他的請求。
重要性;
確保客戶端只與正常的pod進行交互,而且永遠不會知道系統存在問題。
添加的yml文件以下
apiVersion: v1 kind: deployment ... spec: ... port: containers: - name: kubia-yh imgress: luksa/kubia readinessProbe: failureThreshold: 2 httpGet: path: /ping port: 80 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 5 successThreshold: 1 timeoutSeconds: 3
相關參數解釋以下:
HTTP探針在httpGet上的配置項:
模擬就緒探針
# kubectl exec <pod_name> -- curl http://10.187.0.139:80/ping % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
Headless Service
也是一種Service
,但不一樣的是會定義spec:clusterIP: None
,也就是不須要Cluster IP
的Service
。
顧名思義,Headless Service
就是沒頭的Service
。有什麼使用場景呢?
第一種:自主選擇權,有時候client
想本身來決定使用哪一個Real Server
,能夠經過查詢DNS
來獲取Real Server
的信息。
第二種:Headless Services
還有一個用處(PS:也就是咱們須要的那個特性)。Headless Service
的對應的每個Endpoints
,即每個Pod
,都會有對應的DNS
域名;這樣Pod
之間就能夠互相訪問。
emptyDir-用於存儲臨時數據的簡單空目錄
hostPath-用於將目錄從工做節點的文件系統掛載到pod
nfs-掛載到pod中的NFS共享卷。
還有其餘的如gitRepo、gcepersistenDisk
卷的生命週期與pod的生命週期項關聯,因此當刪除pod時,卷的內容就會丟失。
使用empty示例代碼以下:
apiVersion: v1 kind: Pod metadata: name: fortune spec: containers: - image: luksa/fortune name: html-gener volumeMounts: - name: html mountPath: /usr/share/nginx readOnly: true - image: nginx/aplin name: web-service volumeMounts: - name: html mountPath: /usr/share readOnly: true volumes: - name: html //一個名爲html的單獨emptyDir卷,掛載在上面的兩個容器中 emptyDir: {}
hostPath是持久性存儲,emptyDir卷的內容隨着pod的刪除而刪除。
使用hostPath會發現當刪除一個pod,而且下一個pod使用了指向主機上相同路徑的hostPath卷,則新pod將會發現上一個pod留下的數據,但前提是必須將其調度到與第一個pod相同的節點上。
因此當你使用hostPath時請務必考慮清楚,當從新起一個pod時候,必需要保證pod的節點與以前相同。
apiVersion: v1 kind: Pod metadata: name: test-pd spec: containers: - image: k8s.gcr.io/test-webserver name: test-container volumeMounts: - mountPath: /test-pd name: test-volume volumes: - name: test-volume hostPath: # directory location on host path: /data # this field is optional type: Directory
所以必需要將數據存儲在某種類型的網絡存儲(NAS)中。
各類支持的方式不盡相同,例如 GlusterFS 須要建立 Endpoint,Ceph/NFS 之流就沒這麼麻煩了。
以NFS爲例,yml代碼以下:
secret和configmap能夠理解爲特殊的存儲卷,可是它們不是給Pod提供存儲功能的,而是提供了從集羣外部向集羣內部的應用注入配置信息的功能。ConfigMap扮演了K8S集羣中配置中心的角色。ConfigMap定義了Pod的配置信息,能夠以存儲卷的形式掛載至Pod中的應用程序配置文件目錄,從configmap中讀取配置信息;也能夠基於環境變量的形式,從ConfigMap中獲取變量注入到Pod容器中使用。可是ConfigMap是明文保存的,若是用來保存數據庫帳號密碼這樣敏感信息,就很是不安全。通常這樣的敏感信息配置是經過secret
來保存。secret
的功能和ConfigMap同樣,不過secret是經過Base64的編碼機制保存配置信息。
從ConfigMap中獲取配置信息的方法有兩種:
ConfigMap看成存儲卷掛載至Pod中的用法:
apiVersion: v1 kind: Pod metadata: name: pod-configmap-vol-2 labels: name: pod-configmap-vol-2 spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: my-cm-www mountPath: /etc/nginx/conf.d/ # 將名爲my-www的configmap掛載至Pod容器的這個目錄下。 volumes: - name: my-cm-www configMap: # 存儲卷類型選configMap
secert的方法相似,只是secert對數據進行了加密
當集羣用戶須要在其pod中使用持久化存儲時,他們首先建立持久化聲明(PVC)清單,指定所須要的最低容量要求,和訪問模式,而後用戶將持久卷聲明清單提交給kubernetes API服務器,kubernetes將找到能夠匹配的持久卷並將其綁定到持久卷聲明。
持久卷聲明能夠當作pod中的一個捲來使用,其餘用戶不能使用相同的持久卷,除非先經過刪除持久卷聲明綁定來釋放。
下面建立一個 PV mypv1
,配置文件pv1.yml
以下:
apiVersion: v1 kind: PersistentVolume metadata: name: yh_pv1 spec: capacity: storage: 1Gi //capacity 指定 PV 的容量爲 1G accessModes: //accessModes 指定訪問模式爲 ReadWriteOnce - ReadWriteOnce persistentVolumeReclaimpolicy: Recycle //persistentVolumeReclaimPolicy 指定當 PV 的回收策略爲 Recycle storageClassName: nfs //storageClassName 指定 PV 的 class 爲 nfs。至關於爲 PV 設置了一個分類,PVC 能夠指定 class 申請相應 class 的 PV。 nfs: path: /nfs/data //指定 PV 在 NFS 服務器上對應的目錄 server: 10.10.0.11
1.accessModes
指定訪問模式爲 ReadWriteOnce
,支持的訪問模式有:
ReadWriteOnce – PV 能以 read-write 模式 mount 到單個節點。
ReadOnlyMany – PV 能以 read-only 模式 mount 到多個節點。
ReadWriteMany – PV 能以 read-write 模式 mount 到多個節點。
2.persistentVolumeReclaimPolicy
指定當 PV 的回收策略爲 Recycle
,支持的策略有:
Retain – 須要管理員手工回收。
Recycle – 清除 PV 中的數據,效果至關於執行 rm -rf /thevolume/*
。
Delete – 刪除 Storage Provider 上的對應存儲資源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。
建立 pv
:
# kubectl apply -f pv1.yml persistentvolume/yh-pv1 created
查看pv:
# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE yh-pv1 1Gi RWO Recycle Available nfs 17m
STATUS
爲 Available
,表示 yh-pv1就緒,能夠被 PVC 申請。
接下來建立 PVC mypvc1
,配置文件 pvc1.yml
以下:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: yh-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: nfs
PVC 就很簡單了,只須要指定 PV 的容量,訪問模式和 class。
執行命令建立 mypvc1
:
# kubectl apply -f pvc1.yml persistentvolumeclaim/yh-pvc created
查看pvc
# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE yh-pvc Bound yh-pv1 1Gi RWO nfs 64s
從 kubectl get pvc
和 kubectl get pv
的輸出能夠看到 yh-pvc1
已經 Bound 到yh- pv1
,申請成功。
# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE yh-pv1 1Gi RWO Recycle Bound default/yh-pvc nfs 47m
上面已經建立好了pv和pvc,pod中直接使用這個pvc便可
與使用普通 Volume 的格式相似,在 volumes
中經過 persistentVolumeClaim
指定使用 mypvc1
申請的 Volume。
經過命令建立mypod1
:
可見,在 Pod 中建立的文件 /mydata/hello
確實已經保存到了 NFS 服務器目錄 /nfsdata
中。
若是再也不須要使用 PV,可用刪除 PVC 回收 PV。
當 PV 再也不須要時,可經過刪除 PVC 回收。
未刪除pvc以前 pv的狀態是Bound
刪除pvc以後pv的狀態變爲Available,,此時解除綁定後則能夠被新的 PVC 申請。
/nfsdata文件中的文件被刪除了
由於 PV 的回收策略設置爲 Recycle
,因此數據會被清除,但這可能不是咱們想要的結果。若是咱們但願保留數據,能夠將策略設置爲 Retain
。
經過 kubectl apply
更新 PV:
回收策略已經變爲 Retain
,經過下面步驟驗證其效果:
① 從新建立 mypvc1
。
② 在 mypv1
中建立文件 hello
。
③ mypv1
狀態變爲 Released
。
④ PV 中的數據被完整保留。
雖然 mypv1
中的數據獲得了保留,但其 PV 狀態會一直處於 Released
,不能被其餘 PVC 申請。爲了從新使用存儲資源,能夠刪除並從新建立 mypv1
。刪除操做只是刪除了 PV 對象,存儲空間中的數據並不會被刪除。
新建的 mypv1
狀態爲 Available
,已經能夠被 PVC 申請。
PV 還支持 Delete
的回收策略,會刪除 PV 在 Storage Provider 上對應存儲空間。NFS 的 PV 不支持 Delete
,支持 Delete
的 Provider 有 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。
前面的例子中,咱們提早建立了 PV,而後經過 PVC 申請 PV 並在 Pod 中使用,這種方式叫作靜態供給(Static Provision)。
與之對應的是動態供給(Dynamical Provision),即若是沒有知足 PVC 條件的 PV,會動態建立 PV。相比靜態供給,動態供給有明顯的優點:不須要提早建立 PV,減小了管理員的工做量,效率高。
動態供給是經過 StorageClass 實現的,StorageClass 定義瞭如何建立 PV,下面是兩個例子。
StorageClass standard
:
StorageClass slow
:
這兩個 StorageClass 都會動態建立 AWS EBS,不一樣在於 standard
建立的是 gp2
類型的 EBS,而 slow
建立的是 io1
類型的 EBS。不一樣類型的 EBS 支持的參數可參考 AWS 官方文檔。
StorageClass 支持 Delete
和 Retain
兩種 reclaimPolicy
,默認是 Delete
。
與以前同樣,PVC 在申請 PV 時,只須要指定 StorageClass 和容量以及訪問模式,好比:
除了 AWS EBS,Kubernetes 支持其餘多種動態供給 PV 的 Provisioner,完整列表請參考 https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner
下面演示如何爲 MySQL 數據庫提供持久化存儲,步驟爲:
建立 PV 和 PVC。
部署 MySQL。
向 MySQL 添加數據。
模擬節點宕機故障,Kubernetes 將 MySQL 自動遷移到其餘節點。
驗證數據一致性。
首先建立 PV 和 PVC,配置以下:
mysql-pv.yml
mysql-pvc.yml
建立 mysql-pv
和 mysql-pvc
:
接下來部署 MySQL,配置文件以下:
PVC mysql-pvc
Bound 的 PV mysql-pv
將被 mount 到 MySQL 的數據目錄 var/lib/mysql
。
MySQL 被部署到 k8s-node2
,下面經過客戶端訪問 Service mysql
:
kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword
更新數據庫:
① 切換到數據庫 mysql。
② 建立數據庫表 my_id。
③ 插入一條數據。
④ 確認數據已經寫入。
關閉 k8s-node2
,模擬節點宕機故障。
驗證數據的一致性:
因爲node2節點已經宕機,node1節點接管了這個任務。
經過kubectl run 命令 進入node1的這個pod裏,查看數據是否依舊存在
MySQL 服務恢復,數據也無缺無損。
1.瞭解ENTRYPOINT與CMD
ENTRYPOINT定義容器啓動時被調用的能夠執行程序
CMD指定傳遞給ENTRYP的參數
dockerfile 內容以下
FROM daocloud.io/centos:latest ADD aaa /usr/local/aaa CMD ["-f","/var/log/aa.log"] ENTRYPOINT ["tail"]
當啓動鏡像時,容器啓動時執行以下命令:tail -f /var/log/aa.log
或者在docker run <images> <arguments> 中指定,arguments會覆蓋CMD中內容
在k8s中定義容器時,鏡像的ENTRYPOINT和CMD均可以被覆蓋,僅需在容器定義中設置熟悉command和args的值
對應參數以下:
Docker | kubernetes | 描述 |
ENTRYPOINT | command | 容器中運行的可執行文件 |
CMD | args | 傳給可執行文件的參數 |
相關yml代碼以下:
kind: pod spec: containers: - image: some/image command: ["/bin/command"] args: ["args1","args2","args3"]
與容器的命令和參數設置相同,環境變量列表沒法在pod建立後被修改。
在pod的yml文件中設置容器環境變量代碼以下:
kind: pod spec: containers: - image: luksa/fortune:env env: - name: INTERVAL value: "30" name: value-test-yh
使用$( VAR )引用環境變量,
相關ym代碼以下:
env: - name: FIRST_VAR value: "foo" - name: SECOND_VAR value: "$(FIRST_VAR)bar" //最終變量值爲foobar
kubernetes容許將配置選項分離到獨立的資源對象ConfigMap中,本質上就是一個鍵/值對映射,值能夠是短字面變量,也能夠是完整的配置文件。
應用無須直接讀取ConfigMap,甚至根本不須要知道其是否存在。
映射的內容經過環境變量或者卷文件的形式傳遞給容器,而並不是直接傳遞給容器,命令行參數的定義中也是經過$(ENV_VAR)語法變量
使用kubectl creat configmap建立ConfigMap中間不用加-f。
1.使用指令建立ConfigMap
#kubectl creat configmap configmap-yaohong --from-literal=foo=bar --from-literal=sleep-interval=25
2.從文件內容建立ConfigMap條目
#kubectl create configmap my-conf-yh --from-file=config-file.conf
使用以下命令,會將文件內容存儲在自定義的條目下。與字面量使用相同
#kubectl create configmap my-conf-yh --from-file=customkey=config-file.conf
3.從文件夾建立ConfigMap
#kubectl create configmap my-conf-yh --from-file=/path/to/dir
4.合併不一樣選項
#kubectl create configmap my-conf-yh --from-file=/path/to/dir/ --from-file=bar=foobar.conf --from-literal=some=thing
5.獲取ConfigMap
#kubectl -n <namespace> get configmap
引用環境變量中的參數值給當前變量
apiVersion: v1 kind: pod metadata: name: fortune-env-from-configmap spec: containers: - image: luksa/fortune:env env: - name: INTERVAL //設置環境變量 valueFrom: configMapkeyRef: name: fortune-configmap key: sleep-interval //變量的值取自fortune-configmap的slee-interval對應的值
apiVersion: v1 kind: pod metadata: name: fortune-env-from-configmap spec: containers: - image: luksa/fortune:env envFrom: - prefix: CONFIG_ confgMapRef: name: my-confg-map //引用my-config-map的ConfigMap並在變量前面都加上CONFIG_
apiVersion: v1 kind: pod metadata: name: configmap-volume-yh spec: containers: - image: nginx:aplin name: web-server volumeMounts: ... - name: config
defaultMode: "6600" //設置文件的權限爲rw-rw mountPath: /etc/nginx/con.conf
subPath: my.conf //subPath字段能夠用於掛載卷中某個獨立的文件或者文件夾,並且不覆蓋該卷下其餘文件 ... volume: ... - name: config configMap: name: fortune-config //引用fortune-config configMap的卷,而後掛載在/etc/nginx/conf.d
可使用以下命令查看到/etc/nginx/conf.d文件下面包含fortune-config
#kubectl exec config-volume-yh -c web-server ls /etc/nginx/conf.d
Secret結構和ConfigMap相似,均是鍵/值對的映射。
使用方法也和ConfigMap同樣,能夠:
1.將Secret條目做爲環境變量傳遞給容器,
2.將Secret條目暴露爲卷中文件
ConfigMap存儲非敏感的文本配置數據,採用Secret存儲天生敏感的數據
1.查看secret
# kubectl get secrets NAME TYPE DATA AGE default-token-x9cjb kubernetes.io/service-account-token 3 78d
2.描述secret
# kubectl describe secrets default-token-x9cjb Name: default-token-x9cjb Namespace: default Labels: <none> Annotations: kubernetes.io/service-account.name: default kubernetes.io/service-account.uid: 64a41a09-98ce-11e9-9fa5-fa163e6fdb6b Type: kubernetes.io/service-account-token Data ==== token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5lduaW8vc2VydmljZTxCv6HdtP-ZW3ZC2IKKR5YBhaokFIl35mix79pU4Ia2pJ_fuPTBGNyrCHyNQYH4ex5DhND3_b2puQmn8RSErQ ca.crt: 1298 bytes namespace: 7 bytes
1.建立一個名爲https-yh的generic secret
#kubectl create secret generic https-yh --from-file=https.key --from-file=https.cert --from-file=foo
2.建立一個secret.yaml文件,內容用base64編碼
$ echo -n 'admin' | base64 YWRtaW4= $ echo -n '1f2d1e2e67df' | base64 MWYyZDFlMmU2N2Rm
yaml文件內容:
apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: YWRtaW4= password: MWYyZDFlMmU2N2Rm
建立:
$ kubectl create -f ./secret.yaml secret "mysecret" created
解析Secret中內容
$ kubectl get secret mysecret -o yaml apiVersion: v1 data: username: YWRtaW4= password: MWYyZDFlMmU2N2Rm kind: Secret metadata: creationTimestamp: 2016-01-22T18:41:56Z name: mysecret namespace: default resourceVersion: "164619" selfLink: /api/v1/namespaces/default/secrets/mysecret uid: cfee02d6-c137-11e5-8d73-42010af00002 type: Opaque
base64解碼:
$ echo 'MWYyZDFlMmU2N2Rm' | base64 --decode 1f2d1e2e67df
Secret的條目內容會進行Base64格式編碼,而ConfigMap直接以純文本展現。
1.爲二進制數據建立Secret
Base64能夠將二進制數據轉換爲純文本,並以YAML或Json格式進行展現
但要注意Secret的大小限制是1MB
2.stringDate字段介紹
Secret能夠經過StringDate字段設置條目的純文本
kind: Secret apiVersion: v1 stringDate: foo: plain txt date: https.cert: HGIOPUPSDF63456BJ3BBJL34563456BLKJBK634563456BLBKJBLKJ63456BLK3456LK http.key: OHOPGPIU42342345OIVBGOI3456345OVB6O3456BIPO435B6IPU345UI
secret能夠做爲數據卷掛載或者做爲環境變量暴露給Pod中的容器使用,也能夠被系統中的其餘資源使用。好比能夠用secret導入與外部系統交互須要的證書文件等。
在Pod中以文件的形式使用secret
spec.volumes[]
加一個volume,給這個volume起個名字,spec.volumes[].secret.secretName
記錄的是要引用的Secret名字spec.containers[].volumeMounts[]
,指定spec.containers[].volumeMounts[].readOnly = true
,spec.containers[].volumeMounts[].mountPath
要指向一個未被使用的系統路徑。data
字段的每個key都是指定路徑下面的一個文件名下面是一個Pod中引用Secret的列子:
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: mysecret
每個被引用的Secret都要在spec.volumes
中定義
若是Pod中的多個容器都要引用這個Secret那麼每個容器定義中都要指定本身的volumeMounts
,可是Pod定義中聲明一次spec.volumes
就行了。
映射secret key到指定的路徑
能夠控制secret key被映射到容器內的路徑,利用spec.volumes[].secret.items
來修改被映射的具體路徑
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: mysecret items: - key: username path: my-group/my-username
發生了什麼呢?
/etc/foo/my-group/my-username
而不是/etc/foo/username
Secret文件權限
能夠指定secret文件的權限,相似linux系統文件權限,若是不指定默認權限是0644
,等同於linux文件的-rw-r--r--
權限
設置默認權限位
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" volumes: - name: foo secret: secretName: mysecret defaultMode: 256
上述文件表示將secret掛載到容器的/etc/foo
路徑,每個key衍生出的文件,權限位都將是0400
因爲JSON不支持八進制數字,所以用十進制數256表示0400,若是用yaml格式的文件那麼就很天然的使用八進制了
同理能夠單獨指定某個key的權限
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" volumes: - name: foo secret: secretName: mysecret items: - key: username path: my-group/my-username mode: 511
從volume中讀取secret的值
值得注意的一點是,以文件的形式掛載到容器中的secret,他們的值已是通過base64解碼的了,能夠直接讀出來使用。
$ ls /etc/foo/ username password $ cat /etc/foo/username admin $ cat /etc/foo/password 1f2d1e2e67df
被掛載的secret內容自動更新
也就是若是修改一個Secret的內容,那麼掛載了該Secret的容器中也將會取到更新後的值,可是這個時間間隔是由kubelet的同步時間決定的。最長的時間將是一個同步週期加上緩存生命週期(period+ttl)
特例:以subPath形式掛載到容器中的secret將不會自動更新
以環境變量的形式使用Secret
env[].valueFrom.secretKeyRef
指定secret和相應的keyapiVersion: v1 kind: Pod metadata: name: secret-env-pod spec: containers: - name: mycontainer image: redis env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: mysecret key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: mysecret key: password restartPolicy: Never
容器中讀取環境變量,已是base64解碼後的值了:
$ echo $SECRET_USERNAME admin $ echo $SECRET_PASSWORD 1f2d1e2e67df
使用imagePullSecrets
建立一個專門用來訪問鏡像倉庫的secret,當建立Pod的時候由kubelet訪問鏡像倉庫並拉取鏡像,具體描述文檔在 這裏
設置自動導入的imagePullSecrets
能夠手動建立一個,而後在serviceAccount中引用它。全部通過這個serviceAccount建立的Pod都會默認使用關聯的imagePullSecrets來拉取鏡像,
Deployment 的控制器,實際上控制的是 ReplicaSet 的數目,以及每一個 ReplicaSet 的屬性。
而一個應用的版本,對應的正是一個 ReplicaSet;這個版本應用的 Pod 數量,則由 ReplicaSet 經過它本身的控制器(ReplicaSet Controller)來保證。
經過這樣的多個 ReplicaSet 對象,Kubernetes 項目就實現了對多個「應用版本」的描述。
#kubectl rolling-update kubia-v1 kubia-v2 --image=luksa/kubia:v2
使用kubia-v2版本應用來替換運行着kubia-v1的RC,將新的複製控制器命名爲kubia-v2,並使用luksa/kubia:v2最爲鏡像。
#kubectl create -f kubectl.depl-v1.yaml --record //--record能夠記錄歷史版本 #查看Deployment的相關信息 #kubectl get deployment #kubectl describe deployment #查看部署狀態: #kubectl rollout status deployment kubia
#kubectl edit deployment kubia //修改完後資源對象會被更新 #kubectl patch deployment kubia -p '{...}' //只能包含想要更新的字段 #kubectl apply -f kubia-deploy-v2.yml //若是yml中定義的資源不存在,會自動被建立 #kubectl replace -f kubia-deploy-v2.yml //若是yml中定義的資源不存在,則會報錯
#kubectl rollout status deployment kubia
#kubectl rollout undo deployment kubia
#kubectl rollout history deployment kubia
#kubectl rollout undo deployment kubia --to-revision=1
statefulset的建立順序從0到N-1,終止順序則相反,若是須要對satateful擴容,則以前的n個pod必須存在,若是要終止一個pod,則他的後續pod必須所有終止。
建立statefulset
#kubectl create -f ss-nginx.yml
查看statefulset
#kubectl get statefulset
statefulset會使用一個徹底一致的pod來替換被刪除的pod。
statefulset擴容和縮容時,都會刪除最高索引的pod,當這個pod徹底被刪除後,纔回刪除擁有次高索引的pod。
經過DNS中SRV互相發現。
#kuebctl edit statefulset kubia
但修改後pod不會自動 被更新,須要手動delete pod後會從新調度更新。
k8s系統組件之間通訊只能經過API服務器通訊,他們之間不會之間進行通訊。
//獲取Master節點服務健康情況 #kubectl get componentstatuses
關於樂觀鎖併發控制 樂觀鎖併發控制(有時候指樂觀鎖),是指一段數據包含一個版本數字,而不是鎖住該段數據並阻止讀寫操做。每當更新數據,版本數就會增長。當更新數據時,版本就會增長。當更新數據時,就會檢查版本值是否在客戶端讀取數據時間和提交時間之間被增長過。若是增長過,那麼更新會被拒絕,客戶端必須從新讀取新數據,從新嘗試更新。 兩個客戶端嘗試更新同一個數據條目,只有一個會被更新成功。
資源如何存儲在etcd中
flannel操做etcd使用的是v2的API,而kubernetes操做etcd使用的v3的API,因此在下面咱們執行etcdctl
的時候須要設置ETCDCTL_API
環境變量,該變量默認值爲2。
一致性算法要求大部分節點參與,才能進行到下一個狀態,須要有過半的節點參與狀態的更新,因此致使etcd的節點必須爲奇數個。
Kubernetes API服務器爲API對象驗證和配置數據,這些對象包含Pod,Service,ReplicationController等等。API Server提供REST操做以及前端到集羣的共享狀態,全部其它組件能夠經過這些共享狀態交互。
1.API提供RESTful API的形式,進行CRUD(增刪查改)集羣狀態
2.進行校驗
3.處理樂觀鎖,用於處理併發問題,
4.認證客戶端
(1)經過認證插件認證客戶端
(2)經過受權插件認證客戶端
(3)經過准入插件驗證AND/OR修改資源請求
API服務器如何通知客戶端資源變動
API服務器不會去建立pod,同時他不會去管理服務的端點,
它作的是,啓動控制器,以及一些其餘的組件來監控一鍵部署的資源變動,是得組件能夠再集羣元數據變化時候執行任何須要作的任務,
調度器指定pod運行在哪一個集羣節點上。
調度器不會命令選中節點取運行pod,調度器作的就是經過api服務器更新pod的定義。而後api服務器再去通知kubelet該pod已經被調用。當目標節點的kubelet發現該pod被調度到本節點,就會建立並運行pod容器。
調度方法:
1.經過算法過濾全部節點,找到最優節點
2.查找可用節點
(1)是否知足對硬件的資源要求
(2)節點是否資源耗盡
(3)pod是否要求被調度到指定的節點、
(4)是否和要求的lable一致
(5)需求端口是否被佔用
(6)是否有符合要求的存儲卷
(7)是否容忍節點的污染
(1)RC控制器
啓動RC資源的控制器叫作Replication管理器。
RC的操做能夠理解爲一個無限的循環,每次循環,控制器都會查找符合其pod選擇器的pod數量,而且將該數值和指望的複製集數量作比較。
(2)RS控制器
與RC相似
(3)DaemonSet以及job控制器
從他們各自資源集中定義pod模板建立pod資源,
(4)Deployment控制器
Deployment控制器負責使deployment的實際狀態與對應的Deployment API對象指望狀態同步。
每次Deployment對象修改後,Deployment控制器會滾動升級到新的版本。經過建立ReplicaSet,而後按照Deployment中定義的策略同時伸縮新、舊RelicaSet,直到舊pod被新的替代。
(5)StatefulSet控制器
StatefulSet控制器會初始化並管理每一個pod實例的持久聲明字段。
(6)Node控制器
Node控制器管理Node資源,描述了集羣的工做節點。
(7)Service控制器
Service控制器就是用來在loadBalancer類型服務被建立或刪除,從基礎設施服務請求,釋放負載均衡器的。
當Endpoints監聽到API服務器中Aervice資源和pod資源發生變化時,會對應修改、建立、刪除Endpoints資源。
(8)Endpoint資源控制器
Service不會直接鏈接到pod,而是經過一個ip和端口的列表,EedPoint管理器就是監聽service和pod的變化,將ip和端口更新endpoint資源。
(9)Namespace控制器
當收到刪除namespace對象的通知時,控制器經過API服務羣刪除後全部屬於該命名空間的資源。
(10)PV控制器
建立一個持久卷聲明時,就找到一個合適的持久捲進行綁定到聲明。
瞭解kubelet的工做內容
簡單來講,就是負責全部運行在工做節點上的所有內容。
第一個任務,在api服務器中建立一個node資源來註冊該節點;第二任務,持續監控api服務器是否把該節點分配給pod;第三任務,啓動pod;第四任務,持續監控運行的容器,向api服務器報告他們的狀態,事件和資源消耗。
第五任務,kubelet也是運行容器的存活探針的組件,當探針報錯時,他會重啓容器;第六任務,當pod從api服務器刪除時,kubelet終止容器,並通知服務器pod已經終止。
service是一組pod的服務抽象,至關於一組pod的LB,負責將請求分發給對應的pod。service會爲這個LB提供一個IP,通常稱爲cluster IP。
kube-proxy的做用主要是負責service的實現,具體來講,就是實現了內部從pod到service和外部的從node port向service的訪問。
kube-proxy有兩種代理模式,userspace和iptables,目前都是使用iptables。
啓動API服務器時,經過命令行選項能夠開啓認證插件。
瞭解用戶:
分爲兩種鏈接到api服務器的客戶端:
1.真實的人
2.pod,使用一種稱爲ServiceAccount的機制
瞭解組:
認證插件會連同用戶名,和用戶id返回組,組能夠一次性給用戶服務多個權限,不用單次賦予,
system:unauthenticated組:用於全部認證插件都不會認證客戶端身份的請求。
system:authenticated組:會自動分配給一個成功經過認證的用戶。
system:serviceaccount組:包含 全部在系統中的serviceaccount。
system:serviceaccount:<namespace>組:包含了全部在特定命名空間中的serviceAccount。
每一個pod中都包含/var/run/secrets/kubernetes.io/serviceaccount/token文件,以下圖所示,文件內容用於對身份進行驗證,token文件持有serviceaccount的認證token。
應用程序使用token去鏈接api服務器時,認證插件會對serviceaccount進行身份認證,並將serviceaccount的用戶名傳回到api服務器內部。
serviceaccount的用戶名格式以下:
system:serviceaccount:<namespace>:<service account name>
ServiceAccount是運行在pod中的應用程序,和api服務器身份認證的一中方式。
瞭解ServiceAccount資源
ServiceAcount做用在單一命名空間,爲每一個命名空間建立默認的ServiceAccount。
多個pod可使用相同命名空間下的同一的ServiceAccount,
ServiceAccount如何與受權文件綁定
在pod的manifest文件中,能夠指定帳戶名稱的方式,將一個serviceAccount賦值給一個pod,若是不指定,將使用該命名空間下默認的ServiceAccount.
能夠 將不一樣的ServiceAccount賦值給pod,讓pod訪問不一樣的資源。
爲了集羣的安全性,能夠手動建立ServiceAccount,能夠限制只有容許的pod訪問對應的資源。
建立方法以下:
$ kubectl get sa NAME SECRETS AGE default 1 21h $ kubectl create serviceaccount yaohong serviceaccount/yaohong created $ kubectl get sa NAME SECRETS AGE default 1 21h yaohong 1 3s
使用describe來查看ServiceAccount。
$ kubectl describe sa yaohong Name: yaohong Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: yaohong-token-qhbxn //若是強制使用可掛載祕鑰。那麼使用這個serviceaccount的pod只能掛載這個祕鑰 Tokens: yaohong-token-qhbxn Events: <none>
查看該token,
$ kubectl describe secret yaohong-token-qhbxn Name: yaohong-token-qhbxn Namespace: default Labels: <none> Annotations: kubernetes.io/service-account.name: yaohong kubernetes.io/service-account.uid: a3d0d2fe-bb43-11e9-ac1e-005056870b4d Type: kubernetes.io/service-account-token Data ==== ca.crt: 1342 bytes namespace: 7 bytes token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Inlhb2hvbmctdG9rZW4tcWhieG4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoieWFvaG9uZyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImEzZDBkMmZlLWJiNDMtMTFlOS1hYzFlLTAwNTA1Njg3MGI0ZCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0Onlhb2hvbmcifQ.BwmbZKoM95hTr39BuZhinRT_vHF-typH4anjkL0HQxdVZEt_eie5TjUECV9UbLRRYIqYamkSxmyYapV150AQh-PvdcLYPmwKQLJDe1-7VC4mO2IuVdMCI_BnZFQBJobRK9EdPdbZ9uxc9l0RL5I5WyWoIjiwbrQvtCUEIkjT_99_NngdrIr7QD9S5SxHurgE3HQbmzC6ItU911LjmxtSvBqS5NApJoJaztDv0cHKvlT67ZZbverJaStQdxr4yiRbpSycRNArHy-UZKbNQXuzaZczSjVouo5A5hzgSHEBBJkQpQ6Tb-Ko5XGjjCgV_b9uQvhmgdPAus8GdFTTFAbCBw
在pod中定義的spec.serviceAccountName字段上設置,此字段必須在pod建立時設置後續不能被修改。
自定義pod的ServiceAccount的方法以下圖
RBAC受權插件將用戶角色做爲決定用戶可否執行操做的關機因素。
RBAC受權規則經過四種資源來進行配置的,他們能夠分爲兩組:
Role和ClusterRole,他們決定資源上可執行哪些動詞。
RoleBinding和ClusterRoleBinding,他們將上述角色綁定到特定的用戶,組或者ServiceAccounts上。
Role和RoleBinding是namespace級別資源
ClusterRole和ClusterRoleBinding是集羣級別資源
Role資源定義了哪些操做能夠在哪些資源上執行,
建立Role
service-reader.yml
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: kube-system name: service-reader rules: - apiGroups: [""] verbs: ["get", "list"] resources: ["services"]
在kube-system中建立Role
#kubectl -n kube-system create -f service-reader.yml
查看該namespace下的role
$ kubectl -n kube-system get role NAME AGE extension-apiserver-authentication-reader 41h kube-state-metrics-resizer 41h service-reader 2m17s system::leader-locking-kube-controller-manager 41h system::leader-locking-kube-scheduler 41h system:controller:bootstrap-signer 41h system:controller:cloud-provider 41h system:controller:token-cleaner 41h
綁定角色到ServiceAccount
將service-reader角色綁定到default ServiceAccount
$ kubectl create rolebinding test --role=service-reader rolebinding.rbac.authorization.k8s.io/test created
$ kubectl get rolebinding test -o yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: creationTimestamp: 2019-08-11T03:40:51Z name: test namespace: default resourceVersion: "239323" selfLink: /apis/rbac.authorization.k8s.io/v1/namespaces/default/rolebindings/test uid: d0aff243-bbe9-11e9-ac1e-005056870b4d roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: service-reader
查看集羣ClusterRole
# kubectl get clusterrole NAME AGE admin 42h cluster-admin 42h edit 42h flannel 42h kube-state-metrics 42h system:aggregate-to-admin 42h ...
建立ClusterRole
kubectl create clusterrole flannel --verb=get,list -n kube-system
查看yaml文件
# kubectl get clusterrole flannel -o yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRole","metadata":{"annotations":{},"name":"flannel"},"rules":[{"apiGroups":[""],"resources":["pods"],"verbs":["get"]},{"apiGroups":[""],"resources":["nodes"],"verbs":["list","watch"]},{"apiGroups":[""],"resources":["nodes/status"],"verbs":["patch"]}]} creationTimestamp: 2019-08-09T09:58:42Z name: flannel resourceVersion: "360" selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/flannel uid: 45100f6f-ba8c-11e9-8f57-005056870608 rules: - apiGroups: - "" resources: - pods verbs: - get - apiGroups: - "" resources: - nodes verbs: - list - watch - apiGroups: - "" resources: - nodes/status verbs: - patch
建立clusterRoleBinding
$ kubectl create clusterrolebinding cluster-tetst --clusterrole=pv-reader --serviceaccount=kuebsystem:yaohong clusterrolebinding.rbac.authorization.k8s.io/cluster-tetst created
以下所示使用kubectl get clusterroles和kubectl get clusterrolesbinding能夠獲取k8s默認資源。
用edit ClusterRole容許對資源進行修改
用admin ClusterRole賦予一個命名空間所有的權限
$ kubectl get clusterroles NAME AGE admin 44h cluster-admin 44h edit 44h flannel 44h kube-state-metrics 44h system:aggregate-to-admin 44h system:aggregate-to-edit 44h system:aggregate-to-view 44h system:auth-delegator 44h system:aws-cloud-provider 44h system:basic-user 44h system:certificates.k8s.io:certificatesigningrequests:nodeclient 44h system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 44h system:controller:attachdetach-controller 44h system:controller:certificate-controller 44h system:controller:clusterrole-aggregation-controller 44h 。。。
$ kubectl get clusterrolebindings NAME AGE clust-tetst 17m cluster-admin 44h cluster-tetst 13m flannel 44h kube-state-metrics 44h kubelet-bootstrap 44h system:aws-cloud-provider 44h system:basic-user 44h system:controller:attachdetach-controller 44h system:controller:certificate-controller 44h 。。。
在pod的yaml文件中就設置spec.hostNetwork: true
這個時候pod使用宿主機的網絡,若是設置了端口,則使用宿主機的端口。
apiVersion: v1 kind: pod metadata: name: pod-host-yaohong spec: hostNetwork: true //使用宿主節點的網絡命名空間 containers: - image: luksa/kubia command: ["/bin/sleep", "9999"]
在pod的yaml文件中就設置spec.containers.ports字段來設置
在ports字段中可使用
containerPorts設置經過pod 的ip訪問的端口
container.hostPort設置經過所在節點的端口訪問
apiVersion: v1 kind: pod metadata: name: kubia-hostport-yaohong spec: containers: - image: luksa/kubia - name: kubia ports: - containerport: 8080 //該容器經過pod IP訪問該端口 hostport: 9000 //該容器能夠經過它所在節點9000端口訪問 protocol: Tcp
在linux下的多個進程間的通訊機制叫作IPC(Inter-Process Communication),它是多個進程之間相互溝通的一種方法。
apiVersion: v1 kind: pod metadata: name: pod-with-host-pid-and-ipc-yaohong spec: hostPID: true //你但願這個pod使用宿主節點的PID命名空間 hostIPC: true //你但願pod使用宿主節點的IPC命名空間 containers: - name: main image: alpine command: ["/bin/sleep", "99999"]
查看某個pod運行的用戶
$ kubectl -n kube-system exec coredns-7b8dbb87dd-6ll7z id uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
容器的運行用戶再DockerFile中指定,若是沒有指定則爲root
指定pod的運行的用戶方法以下
apiVersion: v1 kind: pod metadata: name: pod-as-user spec: containers: - name: main image: alpine command: ["/bin/sleep", "99999"] securityContext: runAsUser: 405 //你須要指定的用戶ID,而不是用戶名
apiVersion: v1 kind: pod metadata: name: pod-as-user spec: containers: - name: main image: alpine command: ["/bin/sleep", "99999"] securityContext: runAsNonRoot: true //這個容器只容許以非root用戶運行
爲了得到宿主機內核完整的權限,該pod須要在特權模式下運行。須要添加privileged參數爲true。
apiVersion: v1 kind: pod metadata: name: pod-as-privileged spec: containers: - name: main image: alpine command: ["/bin/sleep", "99999"] securityContext: privileged: true //這個容器將在特權模式下運行
apiVersion: v1 kind: pod metadata: name: pod-as-capability spec: containers: - name: main image: alpine command: ["/bin/sleep", "99999"] securityContext: capabilities: //該參數用於pod添加或者禁用某項內核功能 add: - SYS_TIME //添加修改系統時間參數
apiVersion: v1 kind: pod metadata: name: pod-as-capability spec: containers: - name: main image: alpine command: ["/bin/sleep", "99999"] securityContext: capabilities: //該參數用於pod添加或者禁用某項內核功能 drop: - CHOWN //禁用容器修改文件的全部者
apiVersion: v1 kind: pod metadata: name: pod-with-readonly-filesystem spec: containers: - name: main image: alpine command: ["/bin/sleep", "99999"] securityContext: readyOnlyFilesystem: true //這個容器的根文件系統不容許寫入 volumeMounts: - name: my-volume mountPath: /volume //volume寫入是容許的,由於這個目錄掛載一個存儲卷 readOnly: false
PodSecurityPolicy是一種集羣級別(無命名空間)的資源,它定義了用戶可否在pod中使用各類安全相關的特性。
runAsUser: runle: MustRunAs ranges: - min: 2 //添加一個max=min的range,來指定一個ID爲2的user max: 2 fsGroup: rule: MustRunAs ranges: - min: 2 max: 10 //添加多個區間id的限制,爲2-10 或者20-30 - min: 20 max: 30 supplementalGroups: rule: MustRunAs ranges: - min: 2 max: 10 - min: 20 max: 30
三個字段會影響容器的使用
apiVersion: v1 kind: PodSecurityPolicy spec: allowedCapabilities: - SYS_TIME //容許容器添加SYS_time功能 defaultAddCapabilities: - CHOWN //爲每一個容器自動添加CHOWN功能 requiredDropCapabilities: - SYS_ADMIN //要求容器禁用SYS_ADMIN和SYS_MODULE功能
podSelector進行對一個命名空間下的pod進行隔離
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: postgres-netpolicy spec: podSelector: //這個策略確保了對具備app=databases標籤的pod的訪問安全性 matchLabels: app: database ingress: - from: - podSelector: //它只容許來自具備app=webserver標籤的pod的訪問 matchLabels: app: webserver ports: - port: 5432 //容許對這個端口的訪問
namespaceSelector進行對不一樣命名空間間進行網絡隔離
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: postgres-netpolicy spec: podSelector: //這個策略確保了對具備app=databases標籤的pod的訪問安全性 matchLabels: app: database ingress: - from: - namespaceSelector: //只容許tenant: manning標籤的命名空間中運行的pod進行互相訪問 matchLabels: tenant: manning ports: - port: 5432 //容許對這個端口的訪問
ingress: - from: - ipBlock: cidr: 192.168.1.0/24 //指明容許訪問的ip段
使用egress進行限制
spec: podSelector: //這個策略確保了對具備app=databases標籤的pod的訪問安全性 matchLabels: app: database egress: //限制pod的出網流量 - to: - podSelector: matchLables: //database的pod只能與有app: webserver的pod進行通訊 app: webserver