k8s記錄-常識

k8s~術語解釋

簡介

Kubernetes是一個開源的,用於管理雲平臺中多個主機上的容器化的應用,Kubernetes的目標是讓部署容器化的應用簡單而且高效(powerful),Kubernetes提供了應用部署,規劃,更新,維護的一種機制。javascript

Kubernetes一個核心的特色就是可以自主的管理容器來保證雲平臺中的容器按照用戶的指望狀態運行着(好比用戶想讓apache一直運行,用戶不須要關心怎麼去作,Kubernetes會自動去監控,而後去重啓,新建,總之,讓apache一直提供服務),管理員能夠加載一個微型服務,讓規劃器來找到合適的位置,同時,Kubernetes也系統提高工具以及人性化方面,讓用戶可以方便的部署本身的應用(就像canary deployments)。css

節點node

  • master > 負責調度
  • worker > 負責項目運行

Kubernetes節點有運行應用容器必備的服務,而這些都是受Master的控制。
每次個節點上固然都要運行Docker。Docker來負責全部具體的映像下載和容器運行。html

Kubernetes主要由如下幾個核心組件組成:前端

  1. etcd保存了整個集羣的狀態;
  2. apiserver提供了資源操做的惟一入口,並提供認證、受權、訪問控制、API註冊和發現等機制;
  3. controller manager負責維護集羣的狀態,好比故障檢測、自動擴展、滾動更新等;
  4. scheduler負責資源的調度,按照預約的調度策略將Pod調度到相應的機器上;
  5. kubelet負責維護容器的生命週期,同時也負責Volume(CVI)和網絡(CNI)的管理;
  6. Container runtime負責鏡像管理以及Pod和容器的真正運行(CRI);
  7. kube-proxy負責爲Service提供cluster內部的服務發現和負載均衡;

除了核心組件,還有一些推薦的Add-ons:java

  1. kube-dns負責爲整個集羣提供DNS服務
  2. Ingress Controller爲服務提供外網入口
  3. Heapster提供資源監控
  4. Dashboard提供GUI
  5. Federation提供跨可用區的集羣
  6. Fluentd-elasticsearch提供集羣日誌採集、存儲與查詢

術語解釋

  • pods

在Kubernetes中,最小的管理元素不是一個個獨立的容器,而是Pod,Pod是最小的,管理,建立,計劃的最小單元.一個Pod(就像一羣鯨魚,或者一個豌豆夾)至關於一個共享context的配置組,在同一個context下,應用可能還會有獨立的cgroup隔離機制,一個Pod是一個容器環境下的「邏輯主機」,它可能包含一個或者多個緊密相連的應用,這些應用多是在同一個物理主機或虛擬機上。node

  • 同一個Pod中的應用能夠共享磁盤
  • 因爲docker的架構,一個Pod是由多個相關的而且共享磁盤的容器組成
  • Labels

標籤其實就一對 key/value ,被關聯到對象上,好比Pod,標籤的使用咱們傾向於可以標示對象的特殊特色,而且對用戶而言是有意義的(就是一眼就看出了這個Pod是尼瑪數據庫),可是標籤對內核系統是沒有直接意義的。標籤能夠用來劃分特定組的對象(好比,全部女的),標籤能夠在建立一個對象的時候直接給與,也能夠在後期隨時修改,每個對象能夠擁有多個標籤,可是,key值必須是惟一的mysql

  • Namespace

Namespace是對一組資源和對象的抽象集合,好比能夠用來將系統內部的對象劃分爲不一樣的項目組或用戶組。常見的pods, services, replication controllers和deployments等都是屬於某一個namespace的(默認是default),而node, persistentVolumes等則不屬於任何namespacelinux

  • Replication Controller

Replication Controller 保證了在全部時間內,都有特定數量的Pod副本正在運行,若是太多了,Replication Controller就殺死幾個,若是太少了,Replication Controller會新建幾個,和直接建立的pod不一樣的是,Replication Controller會替換掉那些刪除的或者被終止的pod,無論刪除的緣由是什麼(維護阿,更新啊,Replication Controller都不關心)。基於這個理由,咱們建議即便是隻建立一個pod,咱們也要使用Replication Controller。Replication Controller 就像一個進程管理器,監管着不一樣node上的多個pod,而不是單單監控一個node上的pod,Replication Controller 會委派本地容器來啓動一些節點上服務(Kubelet ,Docker)。nginx

  • Node

Node是Pod真正運行的主機,能夠物理機,也能夠是虛擬機。爲了管理Pod,每一個Node節點上至少要運行container runtime(好比docker或者rkt)、kubelet和kube-proxy服務。web

每一個Node都包括如下狀態信息

  1. 地址:包括hostname、外網IP和內網IP
  2. 條件(Condition):包括OutOfDisk、Ready、Me* moryPressure和DiskPressure
  3. 容量(Capacity):Node上的可用資源,包括CPU、內存和Pod總數
  4. 基本信息(Info):包括內核版本、容器引擎版本、OS類型等
  • ReplicaSets

ReplicaSet是下一代複本控制器。ReplicaSet和 Replication Controller之間的惟一區別是如今的選擇器支持。Replication Controller只支持基於等式的selector(env=dev或environment!=qa),但ReplicaSet還支持新的,基於集合的selector(version in (v1.0, v2.0)或env notin (dev, qa))。在試用時官方推薦ReplicaSet。

  • Services

Kubernetes Pod是平凡的,它門會被建立,也會死掉(生老病死),而且他們是不可復活的。 ReplicationControllers動態的建立和銷燬Pods(好比規模擴大或者縮小,或者執行動態更新)。每一個pod都由本身的ip,這些IP也隨着時間的變化也不能持續依賴。這樣就引起了一個問題:若是一些Pods(讓咱們叫它做後臺,後端)提供了一些功能供其它的Pod使用(讓咱們叫做前臺),在kubernete集羣中是如何實現讓這些前臺可以持續的追蹤到這些後臺的?答案是:Service

Kubernete Service 是一個定義了一組Pod的策略的抽象,咱們也有時候叫作宏觀服務。這些被服務標記的Pod都是(通常)經過label Selector決定的(下面咱們會講到咱們爲何須要一個沒有label selector的服務)

  • Volumes

容器中的磁盤的生命週期是短暫的,這就帶來了一系列的問題,第一,當一個容器損壞以後,kubelet 會重啓這個容器,可是文件會丟失-這個容器會是一個全新的狀態,第二,當不少容器在同一Pod中運行的時候,不少時候須要數據文件的共享。Kubernete Volume解決了這個問題.
一個Kubernetes volume,擁有明確的生命週期,與所在的Pod的生命週期相同。所以,Kubernetes volume獨立與任何容器,與Pod相關,因此數據在重啓的過程當中還會保留,固然,若是這個Pod被刪除了,那麼這些數據也會被刪除。更重要的是,Kubernetes volume 支持多種類型,任何容器均可以使用多個Kubernetes volume。

  • Deployment

Deployment爲Pod和ReplicaSet提供了一個聲明式定義(declarative)方法,用來替代之前的ReplicationController來方便的管理應用。典型的應用場景包括:

  1. 定義Deployment來建立Pod和ReplicaSet
    2.滾動升級和回滾應用
  2. 擴容和縮容
  3. 暫停和繼續Deployment
    好比一個簡單的nginx應用能夠定義爲
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 
  • Secret

Secret解決了密碼、token、密鑰等敏感數據的配置問題,而不須要把這些敏感數據暴露到鏡像或者Pod Spec中。Secret能夠以Volume或者環境變量的方式使用。
Secret有三種類型:

  1. Service Account:用來訪問Kubernetes API,由Kubernetes自動建立,而且會自動掛載到Pod的/run/secrets/kubernetes.io/serviceaccount目錄中;
  2. Opaque:base64編碼格式的Secret,用來存儲密碼、密鑰等;
  3. kubernetes.io/dockerconfigjson:用來存儲私有docker registry的認證信息。
  • Ingress

在本篇文章中你將會看到一些在其餘地方被交叉使用的術語,爲了防止產生歧義,咱們首先來澄清下。

  1. 節點:Kubernetes集羣中的服務器;
  2. 集羣:Kubernetes管理的一組服務器集合;
  3. 邊界路由器:爲局域網和Internet路由數據包的路由器,執行防火牆保護局域網絡;
  4. 集羣網絡:遵循Kubernetes網絡模型實現羣集內的通訊的具體實現,好比flannel 和 OVS。
  5. 服務:使用標籤選擇器標識一組pod成爲的Kubernetes Service。 除非另有說明,不然服務的虛擬IP僅可在集羣內部訪問。

什麼是Ingress?
一般狀況下,service和pod的IP僅可在集羣內部訪問。集羣外部的請求須要經過負載均衡轉發到service在Node上暴露的NodePort上,而後再由kube-proxy將其轉發給相關的Pod。

Ingress能夠給service提供集羣外部訪問的URL、負載均衡、SSL終止、HTTP路由等。爲了配置這些Ingress規則,集羣管理員須要部署一個Ingress controller,它監聽Ingress和service的變化,並根據規則配置負載均衡並提供訪問入口。

  • ConfigMap

ConfigMap用於保存配置數據的鍵值對,能夠用來保存單個屬性,也能夠用來保存配置文件。ConfigMap跟secret很相似,但它能夠更方便地處理不包含敏感信息的字符串。

k8s的yaml說明

理解k8s裏的幾個概念

Kubernetes 經過各類 Controller 來管理 Pod 的生命週期。爲了知足不一樣業務場景,Kubernetes 開發了 Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等多種 Controller。最經常使用的 Deployment用來創建Pod,如下是它的步驟

  1. kubectl建立deployment
  2. deployment建立Replcasset
  3. 根據Replicaset建立pod

replicas的命名方式 :deployment名稱+隨機數
pod的命名方式:replicas名稱+隨機數

理解targetport,port,nodeport

targetPort

targetPort很好理解,targetPort是pod上的端口,從port和nodePort上到來的數據最終通過kube-proxy流入到後端pod的targetPort上進入容器。

port

這裏的port表示:service暴露在cluster ip上的端口,:port 是提供給集羣內部客戶訪問service的入口,而在集羣內部,各個服務之間咱們也能夠經過服務名+Port來訪問指定的服務,k8s內部會把服務解析到對應的pod上面。

nodePort

nodePort是kubernetes提供給集羣外部客戶訪問service入口的一種方式(另外一種方式是LoadBalancer),因此,:nodePort 是提供給集羣外部客戶訪問service的入口。

k8s yaml

# yaml格式的pod定義文件完整內容: apiVersion: v1 #必選,版本號,例如v1 kind: Pod #必選,Pod metadata: #必選,元數據  name: string #必選,Pod名稱  namespace: string #必選,Pod所屬的命名空間  labels: #自定義標籤  - name: string #自定義標籤名字  annotations: #自定義註釋列表  - name: string spec: #必選,Pod中容器的詳細定義  containers: #必選,Pod中容器列表  - name: string #必選,容器名稱  image: string #必選,容器的鏡像名稱  imagePullPolicy: [Always | Never | IfNotPresent] #獲取鏡像的策略 Alawys表示下載鏡像 IfnotPresent表示優先使用本地鏡像,不然下載鏡像,Nerver表示僅使用本地鏡像  command: [string] #容器的啓動命令列表,如不指定,使用打包時使用的啓動命令  args: [string] #容器的啓動命令參數列表  workingDir: string #容器的工做目錄  volumeMounts: #掛載到容器內部的存儲卷配置  - name: string #引用pod定義的共享存儲卷的名稱,需用volumes[]部分定義的的卷名  mountPath: string #存儲卷在容器內mount的絕對路徑,應少於512字符  readOnly: boolean #是否爲只讀模式  ports: #須要暴露的端口庫號列表  - name: string #端口號名稱  containerPort: int #容器須要監聽的端口號  hostPort: int #容器所在主機須要監聽的端口號,默認與Container相同  protocol: string #端口協議,支持TCP和UDP,默認TCP  env: #容器運行前需設置的環境變量列表  - name: string #環境變量名稱  value: string #環境變量的值  resources: #資源限制和請求的設置  limits: #資源限制的設置  cpu: string #Cpu的限制,單位爲core數,將用於docker run --cpu-shares參數  memory: string #內存限制,單位能夠爲Mib/Gib,將用於docker run --memory參數  requests: #資源請求的設置  cpu: string #Cpu請求,容器啓動的初始可用數量  memory: string #內存清楚,容器啓動的初始可用數量  livenessProbe: #對Pod內個容器健康檢查的設置,當探測無響應幾回後將自動重啓該容器,檢查方法有exec、httpGet和tcpSocket,對一個容器只需設置其中一種方法便可  exec: #對Pod容器內檢查方式設置爲exec方式  command: [string] #exec方式須要制定的命令或腳本  httpGet: #對Pod內個容器健康檢查方法設置爲HttpGet,須要制定Path、port  path: string  port: number  host: string  scheme: string  HttpHeaders:  - name: string  value: string  tcpSocket: #對Pod內個容器健康檢查方式設置爲tcpSocket方式  port: number  initialDelaySeconds: 0 #容器啓動完成後首次探測的時間,單位爲秒  timeoutSeconds: 0 #對容器健康檢查探測等待響應的超時時間,單位秒,默認1秒  periodSeconds: 0 #對容器監控檢查的按期探測時間設置,單位秒,默認10秒一次  successThreshold: 0  failureThreshold: 0  securityContext:  privileged:false  restartPolicy: [Always | Never | OnFailure]#Pod的重啓策略,Always表示一旦無論以何種方式終止運行,kubelet都將重啓,OnFailure表示只有Pod以非0退出碼退出才重啓,Nerver表示再也不重啓該Pod  nodeSelector: obeject #設置NodeSelector表示將該Pod調度到包含這個label的node上,以key:value的格式指定  imagePullSecrets: #Pull鏡像時使用的secret名稱,以key:secretkey格式指定  - name: string  hostNetwork:false #是否使用主機網絡模式,默認爲false,若是設置爲true,表示使用宿主機網絡  volumes: #在該pod上定義共享存儲卷列表  - name: string #共享存儲卷名稱 (volumes類型有不少種)  emptyDir: {} #類型爲emtyDir的存儲卷,與Pod同生命週期的一個臨時目錄。爲空值  hostPath: string #類型爲hostPath的存儲卷,表示掛載Pod所在宿主機的目錄  path: string #Pod所在宿主機的目錄,將被用於同期中mount的目錄  secret: #類型爲secret的存儲卷,掛載集羣與定義的secre對象到容器內部  scretname: string  items:  - key: string  path: string  configMap: #類型爲configMap的存儲卷,掛載預約義的configMap對象到容器內部  name: string  items:  - key: string  path: string 

這些語法適合於rancher平臺,由於rancher平臺的底層也是k8s爲基礎的。

k8s~k8s裏的服務Service

k8s用命名空間namespace把資源進行隔離,默認狀況下,相同的命名空間裏的服務能夠相互通信,反之進行隔離。

服務Service

1.1 Service

Kubernetes中一個應用服務會有一個或多個實例(Pod,Pod能夠經過rs進行多複本的創建),每一個實例(Pod)的IP地址由網絡插件動態隨機分配(Pod重啓後IP地址會改變)。爲屏蔽這些後端實例的動態變化和對多實例的負載均衡,引入了Service這個資源對象,以下所示:

apiVersion: v1 kind: Service metadata:  name: nginx-svc  labels:  app: nginx spec:  type: ClusterIP  ports:  - port: 80  targetPort: 80  selector: #service經過selector和pod創建關聯  app: nginx 

根據建立Service的type類型不一樣,可分紅4種模式:

  • ClusterIP: 默認方式。根據是否生成ClusterIP又可分爲普通Service和Headless Service兩類:
    • 普通Service:經過爲Kubernetes的Service分配一個集羣內部可訪問的固定虛擬IP(Cluster IP),實現集羣內的訪問。爲最多見的方式。
    • Headless Service:該服務不會分配Cluster IP,也不經過kube-proxy作反向代理和負載均衡。而是經過DNS提供穩定的絡ID來訪問,DNS會將headless service的後端直接解析爲podIP列表。主要供StatefulSet使用。
  • NodePort:除了使用Cluster IP以外,還經過將service的port映射到集羣內每一個節點的相同一個端口,實現經過nodeIP:nodePort從集羣外訪問服務。
  • LoadBalancer:和nodePort相似,不過除了使用一個Cluster IP和nodePort以外,還會向所使用的公有云申請一個負載均衡器(負載均衡器後端映射到各節點的nodePort),實現從集羣外經過LB訪問服務。
  • ExternalName:是 Service 的特例。此模式主要面向運行在集羣外部的服務,經過它能夠將外部服務映射進k8s集羣,且具有k8s內服務的一些特徵(如具有namespace等屬性),來爲集羣內部提供服務。此模式要求kube-dns的版本爲1.7或以上。這種模式和前三種模式(除headless service)最大的不一樣是重定向依賴的是dns層次,而不是經過kube-proxy。
    好比,在service定義中指定externalName的值"my.database.example.com":

此時k8s集羣內的DNS服務會給集羣內的服務名 ..svc.cluster.local 建立一個CNAME記錄,其值爲指定的"my.database.example.com"。
當查詢k8s集羣內的服務my-service.prod.svc.cluster.local時,集羣的 DNS 服務將返回映射的CNAME記錄"foo.bar.example.com"。

備註:
前3種模式,定義服務的時候經過selector指定服務對應的pods,根據pods的地址建立出endpoints做爲服務後端;Endpoints Controller會watch Service以及pod的變化,維護對應的Endpoint信息。kube-proxy根據Service和Endpoint來維護本地的路由規則。當Endpoint發生變化,即Service以及關聯的pod發生變化,kube-proxy都會在每一個節點上更新iptables,實現一層負載均衡。
而ExternalName模式則不指定selector,相應的也就沒有port和endpoints。
ExternalName和ClusterIP中的Headles Service同屬於Headless Service的兩種狀況。Headless Service主要是指不分配Service IP,且不經過kube-proxy作反向代理和負載均衡的服務。

1.2 Port

Service中主要涉及三種Port: * port 這裏的port表示service暴露在clusterIP上的端口,clusterIP:Port 是提供給集羣內部訪問kubernetes服務的入口。

  • targetPort
    containerPort,targetPort是pod上的端口,從port和nodePort上到來的數據最終通過kube-proxy流入到後端pod的targetPort上進入容器。

  • nodePort
    nodeIP:nodePort 是提供給從集羣外部訪問kubernetes服務的入口。

總的來講,port和nodePort都是service的端口,前者暴露給從集羣內訪問服務,後者暴露給從集羣外訪問服務。從這兩個端口到來的數據都須要通過反向代理kube-proxy流入後端具體pod的targetPort,從而進入到pod上的容器內。

1.3 IP

使用Service服務還會涉及到幾種IP:

    • ClusterIP
      Pod IP 地址是實際存在於某個網卡(能夠是虛擬設備)上的,但clusterIP就不同了,沒有網絡設備承載這個地址。它是一個虛擬地址,由kube-proxy使用iptables規則從新定向到其本地端口,再均衡到後端Pod。當kube-proxy發現一個新的service後,它會在本地節點打開一個任意端口,建立相應的iptables規則,重定向服務的clusterIP和port到這個新建的端口,開始接受到達這個服務的鏈接。

    • Pod IP
      Pod的IP,每一個Pod啓動時,會自動建立一個鏡像爲gcr.io/google_containers/pause的容器,Pod內部其餘容器的網絡模式使用container模式,並指定爲pause容器的ID,即:network_mode: "container:pause容器ID",使得Pod內全部容器共享pause容器的網絡,與外部的通訊經由此容器代理,pause容器的IP也能夠稱爲Pod IP。

    • 節點IP
      Node-IP,service對象在Cluster IP range池中分配到的IP只能在內部訪問,若是服務做爲一個應用程序內部的層次,仍是很合適的。若是這個service做爲前端服務,準備爲集羣外的客戶提供業務,咱們就須要給這個服務提供公共IP了。指定service的spec.type=NodePort,這個類型的service,系統會給它在集羣的各個代理節點上分配一個節點級別的端口,能訪問到代理節點的客戶端都能訪問這個端口,從而訪問到服務。

k8s~跨namespace的service相互訪問

在k8s裏,你能夠經過服務名去訪問相同namespace裏的服務,而後服務能夠解析到對應的pod,從而再由pod轉到對應的容器裏,咱們能夠認爲這個過程有兩個port的概念,service port 就是服務的port,在k8s配置文件裏用port表示,還有一個是pod和容器的port,用targetPort表示,其中pod和容器的port你能夠認爲它是一個。

多namespace的service場景

咱們一般會把mysql,redis,rabbitmq,mongodb這些公用組件放在一個namespace裏,或者每一個公用組件都有本身的namespace,而你的業務組件會統一放在本身的namespace裏,這時就涉及到了跨namespace的數據通信問題。

k8s的服務名DNS解析

Kubernetes 目前使用的kube-dns來實現集羣內部的service dns記錄解析。默認狀況下/etc/resolv.conf裏,它的內容是統一的格式。

/ # more /etc/resolv.conf
nameserver 172.19.0.10 search saas.svc.cluster.local svc.cluster.local cluster.local options ndots:5 

search doamin列表默認狀況下,它只包含本地域名。這能夠經過在search關鍵字後面列出所需的域搜索路徑來添加。kubernetes爲每一個容器配置默認是${namespace}.svc.cluster.local svc.cluster.local cluster.local。在一次dns域名查詢時,將會嘗試使用每一個search doamin依次搜索少於ndots點(默認值爲1)的解析器查詢,直到找到匹配項。對於具備多個子域的環境,建議調整選項ndots:n,以免man-in-the-middle攻擊和root-dns-servers的沒必要要通訊。

noots:5

這個咱們能夠把它理解成服務名dns解析的層次,例如{服務名}是一級,而{服務名}.{命名空間}爲二層,{服務名}.{命名空間}.svc.cluster.local是第三層,上面的配置一共有5層,同時也開啓了5層,這樣作能夠保證最大限度的找到你的服務,但對於解析的性能是有影響的。

請注意,若是搜索域對應的服務器不是本地的,那麼這個查詢過程可能會很慢,而且會產生大量的網絡流量。若是其中一個搜索域域沒有可用的服務器,則查詢將超時。

同一集羣跨namespace訪問

若是你要鏈接namespace是redis的,服務名是redis-master的服務,你能夠這樣去配置你的鏈接:

spring: profiles: redis-prod redis: host: redis-master.redis port: 6379 password: 123456 database: 1 

它採用了服務名+命名空間的格式,若是是相同的namespace,能夠直接使用服務名來解析。

k8s~爲服務添加ingress的實現

ingress產生的緣由

ClusterIP的方式只能在集羣內部訪問
NodePort方式的話,測試環境使用還行,當有幾十上百的服務在集羣中運行時,NodePort的端口管理是災難。
LoadBalance方式受限於雲平臺,且一般在雲平臺部署ELB還須要額外的費用。
所幸k8s還提供了一種集羣維度暴露服務的方式,也就是ingress。ingress能夠簡單理解爲service的service,他經過獨立的ingress對象來制定請求轉發的規則,把請求路由到一個或多個service中。這樣就把服務與請求規則解耦了,能夠從業務維度統一考慮業務的暴露,而不用爲每一個service單獨考慮,下面是一個簡單的ingress應用圖,實現了簡單的請求轉發

 ingress和ingress-controller

ingress對象:
指的是k8s中的一個api對象,通常用yaml配置。做用是定義請求如何轉發到service的規則,能夠理解爲配置模板。
ingress-controller:
具體實現反向代理及負載均衡的程序,對ingress定義的規則進行解析,根據配置的規則來實現請求轉發。 
簡單來講,ingress-controller纔是負責具體轉發的組件,經過各類方式將它暴露在集羣入口,外部對集羣的請求流量會先到ingress-controller,而ingress對象是用來告訴ingress-controller該如何轉發請求,好比哪些域名哪些path要轉發到哪些服務等等。

ingress-controller並非k8s自帶的組件,實際上ingress-controller只是一個統稱,用戶能夠選擇不一樣的ingress-controller實現,目前,由k8s維護的ingress-controller只有google雲的GCE與ingress-nginx兩個,其餘還有不少第三方維護的ingress-controller,具體能夠參考 官方文檔。可是無論哪種ingress-controller,實現的機制都大同小異,只是在具體配置上有差別。通常來講,ingress-controller的形式都是一個pod,裏面跑着daemon程序和反向代理程序。daemon負責不斷監控集羣的變化,根據ingress對象生成配置並應用新配置到反向代理,好比nginx-ingress就是動態生成nginx配置,動態更新upstream,並在須要的時候reload程序應用新配置。爲了方便,後面的例子都以k8s官方維護的nginx-ingress爲例。

爲服務添加ingress的實現

1 當咱們爲指定的項目添加ingress支持以後,它會在「負載均衡」標籤頁出現,並顯示出你的域名解析到的服務。

 

2 咱們的ingress是支持https的,因此須要爲你的域名配置對應的證書,咱們在配置文件裏添加

 

 

3 自動爲ingress-controller裏的配置文件添加nginx配置項,而後自動reload它,讓它生效

 

當有新的ingress服務註冊以後,配置文件會發生變化

 

 4 你的服務對應的nginx是在本身服務的ymal裏進行配置的,通常來講,微服務的網關層都應該創建 一個ingress-nginx來對外提供服務!

下面說一下yaml的nginx部分的功能:
  1. 註明ingress的名稱
  2. 填寫以前創建的密文名稱(ingress https 證書)
  3. 填寫你的服務所在的namespace,不寫默認爲default
  4. 填寫你要轉發的服務的域名
  5. 填寫你服務的名稱和pod的端口
 
ymal代碼以下
複製代碼
# 構建反射代理
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: hello-world-ingress
  namespace: saas
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  tls:
    - hosts:
        - www.abc.com
      secretName: saas-tls
  rules:
    - host: www.abc.com
      http:
        paths:
          - backend:
              serviceName: hello-world
              servicePort: 9001
複製代碼
它在ingress-nginx裏生成的完整配置以下
複製代碼
 ## start server www.abc.com
        server {
                server_name www.abc.com ;

                listen 80  ;
                listen [::]:80  ;
                listen 443  ssl http2 ;
                listen [::]:443  ssl http2 ;

                set $proxy_upstream_name "-";

                # PEM sha: c24ba9e405ed77662c0fd7546a908ef45ca76066
                ssl_certificate                         /etc/ingress-controller/ssl/default-fake-certificate.pem;
                ssl_certificate_key                     /etc/ingress-controller/ssl/default-fake-certificate.pem;

                ssl_certificate_by_lua_block {
                        certificate.call()
                }

                location ~* "^/" {

                        set $namespace      "saas";
                        set $ingress_name   "hello-world-ingress";
                        set $service_name   "hello-world";
                set $service_port   "{0 9001 }";
                        set $location_path  "/";

                        rewrite_by_lua_block {
                                lua_ingress.rewrite({
                                        force_ssl_redirect = true,
                                        use_port_in_redirects = false,
                                })
                                balancer.rewrite()
                                plugins.run()
                        }

                        header_filter_by_lua_block {

                                plugins.run()
                        }
                        body_filter_by_lua_block {

                        }

                        log_by_lua_block {

                                balancer.log()

                                monitor.call()

                                plugins.run()
                        }

                        if ($scheme = https) {
                                more_set_headers                        "Strict-Transport-Security: max-age=15724800; includeSubDomains";
                        }

                        port_in_redirect off;

                        set $balancer_ewma_score -1;
                        set $proxy_upstream_name    "saas-hello-world-9001";
                        set $proxy_host             $proxy_upstream_name;
                        set $pass_access_scheme $scheme;
                        set $pass_server_port $server_port;
                        set $best_http_host $http_host;
                        set $pass_port $pass_server_port;

                        set $proxy_alternative_upstream_name "";

                        client_max_body_size                    1m;

                        proxy_set_header Host                   $best_http_host;

                        # Pass the extracted client certificate to the backend

                        # Allow websocket connections
                        proxy_set_header                        Upgrade           $http_upgrade;

                        proxy_set_header                        Connection        $connection_upgrade;

                        proxy_set_header X-Request-ID           $req_id;
                        proxy_set_header X-Real-IP              $the_real_ip;

                        proxy_set_header X-Forwarded-For        $the_real_ip;

                        proxy_set_header X-Forwarded-Host       $best_http_host;
                        proxy_set_header X-Forwarded-Port       $pass_port;
                        proxy_set_header X-Forwarded-Proto      $pass_access_scheme;

                        proxy_set_header X-Original-URI         $request_uri;

                        proxy_set_header X-Scheme               $pass_access_scheme;

                        # Pass the original X-Forwarded-For
                        proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;

                        # mitigate HTTPoxy Vulnerability
                        # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
                        proxy_set_header Proxy                  "";

                        # Custom headers to proxied server

                        proxy_connect_timeout                   5s;
                        proxy_send_timeout                      60s;
                        proxy_read_timeout                      60s;

                        proxy_buffering                         off;
                        proxy_buffer_size                       4k;
                        proxy_buffers                           4 4k;
                        proxy_request_buffering                 on;
                        proxy_http_version                      1.1;

                        proxy_cookie_domain                     off;
                        proxy_cookie_path                       off;

                        # In case of errors try the next upstream server before returning an error
                        proxy_next_upstream                     error timeout;
                        proxy_next_upstream_timeout             0;
                        proxy_next_upstream_tries               3;

                        proxy_pass http://upstream_balancer;

                        proxy_redirect                          off;

                }

        }
        ## end server www.abc.com

 

k8s~kubectl經常使用命令

查看全部 pod 列表, -n 後跟 namespace, 查看指定的命名空間

kubectl get pod kubectl get pod -n kube kubectl get pod -o wide 

查看 RC 和 service 列表, -o wide 查看詳細信息

kubectl get rc,svc kubectl get pod,svc -o wide kubectl get pod <pod-name> -o yaml 

顯示 Node 的詳細信息

kubectl describe node 192.168.0.212 

顯示 Pod 的詳細信息, 特別是查看 pod 沒法建立的時候的日誌

kubectl describe pod <pod-name> eg: kubectl describe pod redis-master-tqds9 

根據 yaml 建立資源, apply 能夠重複執行,create 不行

kubectl create -f pod.yaml kubectl apply -f pod.yaml 

基於 pod.yaml 定義的名稱刪除 pod

kubectl delete -f pod.yaml 

刪除全部包含某個 label 的pod 和 service

kubectl delete pod,svc -l name=<label-name> 

刪除全部 Pod

kubectl delete pod --all 

查看 endpoint 列表

kubectl get endpoints 

執行 pod 的 date 命令

kubectl exec <pod-name> -- date kubectl exec <pod-name> -- bash kubectl exec <pod-name> -- ping 10.24.51.9 

經過bash得到 pod 中某個容器的TTY,至關於登陸容器

kubectl exec -it <pod-name> -c <container-name> -- bash eg: kubectl exec -it redis-master-cln81 -- bash 

查看容器的日誌

kubectl logs <pod-name> kubectl logs -f <pod-name> # 實時查看日誌 kubectl log <pod-name> -c <container_name> # 若 pod 只有一個容器,能夠不加 -c 

查看註釋



kubectl explain pod kubectl explain pod.apiVersion

k8s~helm的介紹

Helm 是什麼

  1. Helm 是 Deis 開發的一個用於 Kubernetes 應用的包管理工具,主要用來管理 Charts。有點相似於 Ubuntu 中的 APT 或 CentOS 中的 YUM。
  2. Helm Chart 是用來封裝 Kubernetes 原生應用程序的一系列 YAML 文件。能夠在你部署應用的時候自定義應用程序的一些 Metadata,以便於應用程序的分發。
    對於應用發佈者而言,能夠經過 Helm 打包應用、管理應用依賴關係、管理應用版本併發布應用到軟件倉庫。
  3. 對於使用者而言,使用 Helm 後不用須要編寫複雜的應用部署文件,能夠以簡單的方式在 Kubernetes 上查找、安裝、升級、回滾、卸載應用程序。

作爲 Kubernetes 的一個包管理工具,Helm具備以下功能:

  1. 建立新的 chart
  2. chart 打包成 tgz 格式
  3. 上傳 chart 到 chart 倉庫或從倉庫中下載 chart
  4. 在Kubernetes集羣中安裝或卸載 chart
  5. 管理用Helm安裝的 chart 的發佈週期

Helm 組件及相關術語

本文中講到的是helm V2最新版本,V3版本也已經發布了beta版,在 Helm 3 中,Tiller 被移除了。

  • Helm
    Helm 是一個命令行下的客戶端工具。主要用於 Kubernetes 應用程序 Chart 的建立、打包、發佈以及建立和管理本地和遠程的 Chart 倉庫。

  • Tiller
    Tiller 是 Helm 的服務端,部署在 Kubernetes 集羣中。Tiller 用於接收 Helm 的請求,並根據 Chart 生成 Kubernetes 的部署文件( Helm 稱爲 Release ),而後提交給 Kubernetes 建立應用。Tiller 還提供了 Release 的升級、刪除、回滾等一系列功能。

  • Chart
    包含了建立Kubernetes的一個應用實例的必要信息,Helm 的軟件包,採用 TAR 格式。相似於 APT 的 DEB 包或者 YUM 的 RPM 包,其包含了一組定義 Kubernetes 資源相關的 YAML 文件。

  • Repoistory
    Helm 的軟件倉庫,Repository 本質上是一個 Web 服務器,該服務器保存了一系列的 Chart 軟件包以供用戶下載,而且提供了一個該 Repository 的 Chart 包的清單文件以供查詢。Helm 能夠同時管理多個不一樣的 Repository。

  • Release
    是一個 chart 及其配置的一個運行實例,使用 helm install 命令在 Kubernetes 集羣中部署的 Chart 稱爲 Release。

Helm 工做流程

    • Chart Install 過程
      Helm 從指定的目錄或者 TAR 文件中解析出 Chart 結構信息。
      Helm 將指定的 Chart 結構和 Values 信息經過 gRPC 傳遞給 Tiller。
      Tiller 根據 Chart 和 Values 生成一個 Release。
      Tiller 將 Release 發送給 Kubernetes 用於生成 Release。

    • Chart Update 過程
      Helm 從指定的目錄或者 TAR 文件中解析出 Chart 結構信息。
      Helm 將須要更新的 Release 的名稱、Chart 結構和 Values 信息傳遞給 Tiller。
      Tiller 生成 Release 並更新指定名稱的 Release 的 History。
      Tiller 將 Release 發送給 Kubernetes 用於更新 Release。

    • Chart Rollback 過程
      Helm 將要回滾的 Release 的名稱傳遞給 Tiller。
      Tiller 根據 Release 的名稱查找 History。
      Tiller 從 History 中獲取上一個 Release。
      Tiller 將上一個 Release 發送給 Kubernetes 用於替換當前 Release。

    • Chart 處理依賴說明
      Tiller 在處理 Chart 時,直接將 Chart 以及其依賴的全部 Charts 合併爲一個 Release,同時傳遞給 Kubernetes。所以 Tiller 並不負責管理依賴之間的啓動順序。Chart 中的應用須要可以自行處理依賴關係。

k8s~helm的安裝過程

上一講說了一些helm的基本概念,而今天主要說一下如何把helm部署到服務器上,在helm3以前的版本里,它由客戶端helm和服務端tiller組成,而helm3.0以後它去掉了tiller,而直接與k8s通信,能夠說在部署上更簡單了,而今天咱們主要仍是部署2.x版本的helm.

下載安裝包

https://get.helm.sh/helm-v2.16.5-linux-amd64.tar.gz 

腳本文檔rbac-config.yml

apiVersion: v1 kind: ServiceAccount metadata:  name: tiller  namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata:  name: tiller roleRef:  apiGroup: rbac.authorization.k8s.io  kind: ClusterRole  name: cluster-admin subjects:  - kind: ServiceAccount  name: tiller  namespace: kube-system 

構建rbac

kubectl create -f rbac-config.yaml 

初始化tiller

helm init --service-account tiller --skip-refresh 

對於 Kubernetes v1.16.0 以上的版本,有可能會碰到 Error: error installing: the server could not find the requested resource 的錯誤。這是因爲 extensions/v1beta1 已經被 apps/v1 替代。相信在2.15 或者 3 版本發佈以後, 應該就不會遇到這個問題了。仍是生態比較慢的緣由。

從新初始化tiller

helm init -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.14.3 --stable-repo-url http://mirror.azure.cn/kubernetes/charts/ --service-account tiller --override spec.selector.matchLabels.'name'='tiller',spec.selector.matchLabels.'app'='helm' --output yaml | sed 's@apiVersion: extensions/v1beta1@apiVersion: apps/v1@' | kubectl apply -f - 

查看tiller的pod信息

kubectl get pods -n kube-system | grep tiller tiller-deploy-7c7b67c9fd-kxh6p 1/1 Running 0 4m58s 

到如今爲止,咱們的helm就安裝功能了,以後咱們裝運行helm來進行charts的安裝

k8s~helm3更方便的部署

上級講了helm2的安裝,而且在安裝過程當中可能會出現問題,主要是與k8s版本衝突的問題,而最新的helm3對整個helm的架構都有了一個改進,它只有一個客戶端的helm程序,由它進行鏈接k8s集羣,完成對charts的部署工做。

下載helm3

https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz 

查看配置信息

[root@i-pcwovafu bin]# helm env HELM_NAMESPACE="default" HELM_KUBECONTEXT="" HELM_BIN="helm" HELM_DEBUG="false" HELM_PLUGINS="/root/.local/share/helm/plugins" HELM_REGISTRY_CONFIG="/root/.config/helm/registry.json" HELM_REPOSITORY_CACHE="/root/.cache/helm/repository" HELM_REPOSITORY_CONFIG="/root/.config/helm/repositories.yaml" 

添加公用的倉庫

helm repo add stable http://mirror.azure.cn/kubernetes/charts helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts helm repo update 

指定對應的k8s集羣

這一步很是關鍵,它是helm與k8s通信的保證,這一步就是把k8s環境變量KUBECONFIG進行配置

export KUBECONFIG=/root/.kube/config #能夠寫到/etc/profile裏 

查詢一個charts

[root@i-pcwovafu ~]# helm search hub nginx URL CHART VERSION APP VERSION DESCRIPTION https://hub.helm.sh/charts/choerodon/nginx-file... 0.1.0 1.13.5-alpine A Helm chart for Kubernetes https://hub.helm.sh/charts/cloudposse/nginx-ing... 0.1.8 A Helm chart for Nginx Ingress https://hub.helm.sh/charts/cloudposse/nginx-def... 0.5.0 A Helm chart for nginx-default-backend to be us... https://hub.helm.sh/charts/cloudposse/fail-whale 0.1.1 A Helm chart that provides a mainte 

構建一個nginx的用例

helm create nginx helm nignx-demo ./nginx 

查詢咱們的nginx pod

[root@i-pcwovafu bin]# rancher kubectl get pods -n default NAME READY STATUS RESTARTS AGE web-nginx-858f7d9cc5-hlhkj 1/1 Running 0 2m14s 

也可使用helm命令來查看

[root@i-pcwovafu bin]# helm list NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION web-nginx default 1 2020-04-07 17:09:53.480335758 +0800 CST deployed nginx-0.1.0 1.16.0 

這樣一個最簡單的helm應用就創建好了!

k8s~helm構建一個應用

三個概念

  1. chart:包含了建立Kubernetes的一個應用實例的必要信息
  2. config:包含了應用發佈配置信息
  3. release:是一個chart及其配置的一個運行實例

創建一個helm charts

helm create hello-world 
  • Chart.yaml 用於描述這個Chart的相關信息,包括名字、描述信息以及版本等。
    僅僅是一些簡單的文本描述

  • values.yaml 用於存儲 templates 目錄中模板文件中用到變量的值。

  • NOTES.txt 用於介紹 Chart 部署後的一些信息,例如:如何使用這個 Chart、列出缺省的設置等。

  • Templates 目錄下是 YAML 文件的模板,該模板文件遵循 Go template 語法。

Templates 目錄下 YAML 文件模板的值默認都是在 values.yaml 裏定義的,好比在 deployment.yaml 中定義的容器鏡像。
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
其中的 .Values.image.repository 的值就是在 values.yaml 裏定義的 nginx,.Values.image.tag 的值就是 stable。
以上兩個變量值是在 create chart 的時候就自動生成的默認值,你能夠根據實際狀況進行修改。實際上都是靜態文本,只在是執行的時候才被解析.

構建一個helm應用

打開 Chart.yaml,能夠看到內容以下,配置名稱和版本

apiVersion: v1 appVersion: "1.0" description: A Helm chart for Kubernetes name: mychart version: 0.1.0 

編輯 values.yaml,它默認會在 Kubernetes 部署一個 Nginx。下面是 mychart 應用的 values.yaml 文件的內容:

$ cat mychart/values.yaml # Default values for mychart. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 image:  repository: nginx  tag: stable  pullPolicy: IfNotPresent service:  type: ClusterIP  port: 80 ingress:  enabled: false  annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true"  path: /  hosts:  - chart-example.local  tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local resources: {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following # lines, adjust them as necessary, and remove the curly braces after 'resources:'. # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi nodeSelector: {} tolerations: [] affinity: {} 

檢查模塊配置

$ helm lint hello-world/ 

打包

helm package hello-world helm package mychart --debug #顯示詳細信息 

啓動helm本地倉庫(helm3已被移除)

helm serve  --repo-path /data/helm/repository/ --url http://172.17.0.22:8879/charts/ & 

倉庫刷新和查詢應用

$ helm repo update $ helm search mychart NAME CHART VERSION APP VERSION DESCRIPTION local/hello-world 0.1.0 1.0 A Helm chart for Kubernetes 

在 Kubernetes 中部署應用

Chart 被髮布到倉儲後,就能夠經過 helm install 命令部署該 Chart。

helm install hello local/hello-world 

查看Release的狀態信息

helm status wordpress 

升級charts

helm upgrade  wordpress stable/wordpress
helm upgrade --install --force hello-world ./hello.tgz --namespace test # 也能夠指定命名空間和它的taz包 

回滾到上一個版本



helm rollback hello-world 1 # 向上歸滾一個版本

k8s~helm裏的yaml的介紹

Chart.yaml 文件做用

  1. name: [必須] Chart的名稱
  2. version: [必須] Chart的版本號,版本號必須符合 SemVer 2:http://semver.org/
  3. description: [可選] Chart的簡要描述
  4. keywords: - [可選] 關鍵字列表,便於檢索
  5. home: [可選] 項目地址
  6. sources: - [可選] 當前Chart的下載地址列表

charts依賴

能夠在requirements.yaml裏去配置它的依賴關係, 它支持兩種方式表示依賴關係,可使用requirements.yaml或者直接將依賴的Chart放置到charts目錄中。

dependencies: - name: mariadb version: 7.x.x repository: https://kubernetes-charts.storage.googleapis.com/ condition: mariadb.enabled tags: - wordpress-database 

templates 目錄

templates目錄下的yaml文件,遵循Go template語法。使用過Hugo的靜態網站生成工具的人應該對此很熟悉。
templates目錄中存放了Kubernetes部署文件的模版,好比deployment.yaml,service.yaml等,它裏面引用的變量來自values.yaml裏

  • 生成最終的yaml文件-文本對齊
    {{ include "test" | indent 4}}
  • 生成最終的yaml文件-去除空行
    {{- define "test" -}}模版內容{{- end -}}
  • 變量(默認值)的使用
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 

上面的{{ .Values.image.repository }}表示values.yaml文件裏的image節點下的repository元素的內容

數據卷Volume、數據卷聲明VolumeClaim

k8s應用(包括有狀態跟無狀態應用),須要使用數據卷的話,須要在存儲卷中進行設置和聲明,下面列出持久化數據卷的聲明跟設置的模板:

數據卷設置:

apiVersion: v1 kind: PersistentVolume -這裏說明是持久化數據卷 metadata:  finalizers:  - kubernetes.io/pv-protection  labels:  alicloud-pvname: {{ .Values.volumes.name }} -數據卷標籤,eg:XXX-data  name: {{ .Values.volumes.name }} -數據卷名稱,eg:XXX-data spec:  accessModes:  - ReadWriteMany                           -權限  capacity:  storage: {{ .Values.volumes.storage }} -容量大小,eg:10Gi  flexVolume:  driver: alicloud/nas -數據卷類型是nas  options:  path: {{ .Values.volumes.path }} -數據卷路徑,eg:/tmp  server: {{ .Values.volumes.server }} -數據卷服務商,eg:xxxxx.nas.aliyuncs.com  vers: '3'  persistentVolumeReclaimPolicy: Retain  storageClassName: nas 

數據卷聲明:

apiVersion: v1 kind: PersistentVolumeClaim -持久化數據卷聲明 metadata: annotations: pv.kubernetes.io/bind-completed: 'yes' pv.kubernetes.io/bound-by-controller: 'yes' finalizers: - kubernetes.io/pvc-protection name: {{ .Values.volumes.name }} spec: accessModes: - ReadWriteMany resources: requests: storage: {{ .Values.volumes.storage }} -容量,eg:10Gi selector: matchLabels: alicloud-pvname: {{ .Values.volumes.name }} storageClassName: nas volumeName: {{ .Values.volumes.name }} 

伸縮配置 HorizontalPodAutoscaler

應用彈性伸縮配置,這個能夠配置最大、最小副本集跟伸縮條件的參數到values.yaml文件裏面

kind: HorizontalPodAutoscaler apiVersion: autoscaling/v1 metadata:  name: {{ include "admin.appname" . }}-hpa -admin.appname就是後面執行helm命令的時候倒數第二個參數,爲何前面是admin呢,admin就是你配置Chart.yaml的時候裏面的name變量的值 spec:  scaleTargetRef:  kind: Deployment  name: {{ include "admin.appname" . }}  apiVersion: apps/v1beta2  minReplicas: 1 -最小副本集  maxReplicas: 10 -最大副本集  targetCPUUtilizationPercentage: 70 -伸縮條件 

配置項ConfigMap

配置項設置,通常每一個項目有都對應的環境參數,好比:數據庫、redis等這些帳號密碼類的參數,這些能夠抽離出來當成一個配置項處理

apiVersion: v1 kind: ConfigMap metadata:  name: {{ .Values.envConfigName }}          -每一個環境就配置一個配置項 data: {{- range $k, $v := .Values.configDatas }}      -這裏是循環遍歷configDatas這個變量 {{ $k | indent 2 }}.yml: >-               -下面這兩行配置一個key->value的配置項(即文件名->文件內容) {{ $v | indent 4 }} {{- end -}} 

鏡像密碼配置Secret

將鏡像的密碼配置到保密字典中

apiVersion: v1 kind: Secret metadata: name: image-secret -name隨意寫 data: .dockerconfigjson: {{ .Files.Get "image.pwd" | b64enc }} -內容 type: kubernetes.io/dockerconfigjson 

TLs證書配置(後面配置ingress的時候要用到,否則沒法用https)

apiVersion: v1 kind: Secret metadata:  name: tls-secret data: tls.crt: {{ .Files.Get "XXXXX.com.pem" | b64enc }} tls.key: {{ .Files.Get "XXXXX.com.key" | b64enc }} type: Opaque 

下次主要說一下幾個重要的yaml文件的模板。

相關文章
相關標籤/搜索