Kubernets-K8S(TKE)實踐之路

文章目錄

目的篇

本文再githup上持續更新 https://github.com/ROOT137/Docker

現有體系分析
  • 成本伴隨着服務規模的擴大會越來越高
  • 服務器規模伴隨着服務規模的擴大會越來越龐大
  • 虛擬機性能利用率不高
  • 無法自動擴容,自動調度,自動重啓
期望Docker+Kubernetes的效果
  • 快速部署應用,快速擴展應用
  • 無縫對接新的應用功能節省資源,優化硬件資源的使用
  • 交付、部署:虛擬機可以通過鏡像實現環境交付的一致性
  • 可擴展: 模塊化,插件化,可掛載,可組合
  • 自動化: 自動部署,自動重啓,自動複製,自動伸縮/擴展

傳統虛擬化與Docker對比

在這裏插入圖片描述在這裏插入圖片描述

虛擬機概述

虛擬機在本質上就是在模擬一臺真實的計算機設備,同時遵循同樣的程序執行方式。虛擬機能夠利用“虛擬機管理程序”運行在物理設備之上。反過來,虛擬機管理程序則可運行在主機設備或者“裸機”之上。
傳統的虛擬機需要模擬整臺機器包括硬件,每臺虛擬機都需要有自己的操作系統,虛擬機一旦被開啓,預分配給他的資源將全部被佔用。,每一個虛擬機包括應用,必要的二進制和庫,以及一個完整的用戶操作系統。

Docker虛擬化的架構

其中Docker Engine可以簡單看成對Linux的NameSpace、Cgroup、鏡像管理文件系統操作的封裝。Docker並沒有和虛擬機一樣利用一個完全獨立的Guest OS實現環境隔離,它利用的是目前linux內核本身支持的容器方式實現資源和環境隔離。簡單的說,Docker是利用namespace實現系統環境的隔離;利用Cgroup實現資源限制;利用鏡像實現根目錄環境的隔離。

docker化優點
  • Docker啓動快速屬於秒級別。虛擬機通常需要幾分鐘去啓動。

  • Docker在操作系統級別進行虛擬化,Docker容器和內核交互,幾乎沒有性能損耗,性能優於通過Hypervisor層與內核層的虛擬化。

  • Docker更輕量,Docker的架構可以共用一個內核與共享應用程序庫,所佔內存極小。同樣的硬件環境,Docker運行的鏡像數遠多於虛擬機數量。對系統的利用率非常高。與虛擬機相比,Docker隔離性更弱,Docker屬於進程之間的隔離,虛擬機可實現系統級別隔離。

  • 安全性:Docker的安全性也更弱。Docker的租戶root和宿主機root等同,一旦容器內的用戶從普通用戶權限提升爲root權限,它就直接具備了宿主機的root權限,進而可進行無限制的操作。虛擬機租戶root權限和宿主機的root虛擬機權限是分離的,並且虛擬機利用如Intel的VT-d和VT-x的ring-1硬件隔離技術,這種隔離技術可以防止虛擬機突破和彼此交互,而容器至今還沒有任何形式的硬件隔離,這使得容器容易受到攻擊。

  • 可管理性:Docker的集中化管理工具還不算成熟。各種虛擬化技術都有成熟的管理工具,例如VMware vCenter提供完備的虛擬機管理能力。

  • 高可用和可恢復性:Docker對業務的高可用支持是通過快速重新部署實現的。虛擬化具備負載均衡、高可用、容錯、遷移和數據保護等經過生產實踐檢驗的成熟保障機制,VMware可承諾虛擬機99.999%高可用,保證業務連續性。

  • 快速創建、刪除:虛擬化創建是分鐘級別的,Docker容器創建是秒級別的,Docker的快速迭代性,決定了無論是開發、測試、部署都可以節約大量時間。

  • 交付、部署:虛擬機可以通過鏡像實現環境交付的一致性,但鏡像分發無法體系化;Docker在Dockerfile中記錄了容器構建過程,可在集羣中實現快速分發和快速部署。

K8S 優點

  • 快速部署應用,快速擴展應用
  • 無縫對接新的應用功能節省資源,優化硬件資源的使用
  • 可移植: 支持公有云,私有云,混合雲,多重雲(multi-cloud)
  • 可擴展: 模塊化,插件化,可掛載,可組合
  • 自動化: 自動部署,自動重啓,自動複製,自動伸縮/擴展

概念篇

Dcoker相關

Dcoker是什麼

Docker是一個集開發、打包、運行應用於一體的開放式平臺。Docker可以用來快速交付應用。使用Docker,你可以將應用程序從你的基礎設施中分離出來,並將基礎設施當做一個管理平臺。Docker可以加快打包時間,加快測試,加快發佈,縮短開發及運行代碼之間的週期。Docker通過結合內核容器化特點和工作流,並使之工具化來實現這一切,幫助管理和發佈你的應用。

Docker 鏡像

Docker鏡像是一個只讀的模板。包含了容器運行時所需要的文件系統和一些參數。鏡像是無狀態的,也不會改變。鏡像是用來創建容器的。你可以使用docker pull命令獲取一個別人已創建好的鏡像,或者使用dockerbuild來構建一個自己的鏡像。

Docker 容器

Docker容器就像是一個文件夾,容器中包含了應用運行所需的一切。每個容器都是一個隔離的和安全的應用平臺。容器是鏡像的一個實例,它是有狀態的,而且隨時會改變,容器一般是短暫的。

Docker Daemon

Docker Daemon直接將執行命令發送至Docker Client——例如構建、運行以及分發等等。Docker Daemon運行在主機設備之上,但作爲用戶,我們永遠不會直接與該Daemon進行通信。Docker Client也可以運行在主機設備上,但並非必需。它亦能夠運行在另一臺設備上,並與運行在目標主機上的Docker Daemon進行遠程通信。

Docker Client

Docker Client是我們作爲最終用戶的通信對象。我們可以將其視爲Docker的UI。我們進行的一切操作都將直接接入Docker Client,再由其將指令傳遞至Docker Daemon。

Docker API

用於同Docker Daemon遠程交互。

Docker 應用場景
  • web應用的自動化打包和發佈;
  • 自動化測試和持續集成、發佈;
  • 在服務型環境中部署和調整數據庫或其他的後臺應用;
  • 從頭編譯或者擴展現有的OpenShift或Cloud Foundry平臺來搭建自己的PaaS環境。

Kubernetes相關

K8S是什麼

Kubernetes是容器集羣管理系統,是一個開源的平臺,可以實現容器集羣的自動化部署、自動擴縮容、維護等功能。
Kubernetes是Google 2014年創建管理的,是Google 10多年大規模容器管理技術Borg的開源版本

TKE是什麼

騰訊雲容器服務(Tencent Kubernetes Engine,TKE)基於原生 kubernetes 提供以容器爲核心的、高度可擴展的高性能容器管理服務。騰訊雲容器服務完全兼容原生 kubernetes API ,擴展了騰訊雲的 CBS、CLB 等 kubernetes 插件,爲容器化的應用提供高效部署、資源調度、服務發現和動態伸縮等一系列完整功能,解決用戶開發、測試及運維過程的環境一致性問題,提高了大規模容器集羣管理的便捷性,幫助用戶降低成本,提高效率。容器服務提供免費使用,涉及的其他雲產品另外單獨計費。

K8S架構圖及應用集羣節點說明

在這裏插入圖片描述

Pod

pod運行在Node上,包含一組容器和卷。同一個Pod裏的容器共享同一個網絡命名空間,可以使用localhost互相通信。Pod是短暫的,不是持續性實體。你可能會有這些問題:

  • 如果Pod是短暫的,那麼我怎麼才能持久化容器數據使其能夠跨重啓而存在呢? 是的,Kubernetes支持卷的概念,因此可以使用持久化的卷類型。
  • 是否手動創建Pod,如果想要創建同一個容器的多份拷貝,需要一個個分別創建出來麼?可以手動創建單個Pod,但是也可以使用Replication Controller使用Pod模板創建出多份拷貝
  • 如果Pod是短暫的,那麼重啓時IP地址可能會改變,那麼怎麼才能從前端容器正確可靠地指向後臺容器呢?這時可以使用Service

Pod的生命週期:

  • Pending Pod:Pod已經被創建,但是一個或多個容器還未創建,包括Pod調度階段,以及容器鏡像的下載過程
  • Running: Pod已經被調度到Node,所有容器已經創建,並且至少一個容器在運行或者正在重啓。
  • Successded: Pod中所有容器正常退出
  • Failed: Pod中所有容器推出,至少有一個容器時一次退出的
Lable

一些Pod有Label([外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BaN3FLeV-1589009640677)(en-resource://database/730:1)])。一個Label是attach到Pod的一對鍵/值對,用來傳遞用戶定義的屬性。比如,你可能創建了一個"tier"和“app”標籤,通過Label(tier=frontend, app=myapp)來標記前端Pod容器,使用Label(tier=backend, app=myapp)標記後臺Pod。然後可以使用Selectors選擇帶有特定Label的Pod,並且將Service或者Replication Controller應用到上面。

Replication Controller

是否手動創建Pod,如果想要創建同一個容器的多份拷貝,需要一個個分別創建出來麼,能否將Pods劃到邏輯組裏?
Replication Controller確保任意時間都有指定數量的Pod“副本”在運行。如果爲某個Pod創建了Replication Controller並且指定3個副本,它會創建3個Pod,並且持續監控它們。如果某個Pod不響應,那麼Replication Controller會替換它,保持總數爲3.如下面的動畫所示:
在這裏插入圖片描述

如果之前不響應的Pod恢復了,現在就有4個Pod了,那麼Replication Controller會將其中一個終止保持總數爲3。如果在運行中將副本總數改爲5,Replication Controller會立刻啓動2個新Pod,保證總數爲5。還可以按照這樣的方式縮小Pod,這個特性在執行滾動升級時很有用。
當創建Replication Controller時,需要指定兩個東西:

  • Pod模板:用來創建Pod副本的模板

  • Label:Replication Controller需要監控的Pod的標籤。
    現在已經創建了Pod的一些副本,那麼在這些副本上如何均衡負載呢?我們需要的是Service

    Service

如果Pods是短暫的,那麼重啓時IP地址可能會改變,怎麼才能從前端容器正確可靠地指向後臺容器呢?
Service是定義一系列Pod以及訪問這些Pod的策略的一層抽象。Service通過Label找到Pod組。因爲Service是抽象的,所以在圖表裏通常看不到它們的存在,這也就讓這一概念更難以理解。
現在,假定有2個後臺Pod,並且定義後臺Service的名稱爲‘backend-service’,lable選擇器爲(tier=backend, app=myapp)。backend-service 的Service會完成如下兩件重要的事情:

  • 會爲Service創建一個本地集羣的DNS入口,因此前端Pod只需要DNS查找主機名爲 ‘backend-service’,就能夠解析出前端應用程序可用的IP地址。

  • 現在前端已經得到了後臺服務的IP地址,但是它應該訪問2個後臺Pod的哪一個呢?Service在這2個後臺Pod之間提供透明的負載均衡,會將請求分發給其中的任意一個(如下面的動畫所示)。通過每個Node上運行的代理(kube-proxy)完成。這裏有更多技術細節。

下述動畫展示了Service的功能。注意該圖作了很多簡化。如果不進入網絡配置,那麼達到透明的負載均衡目標所涉及的底層網絡和路由相對先進。如果有興趣,這裏有更深入的介紹。
在這裏插入圖片描述
有一個特別類型的Kubernetes Service,稱爲'LoadBalancer',作爲外部負載均衡器使用,在一定數量的Pod之間均衡流量。比如,對於負載均衡Web流量很有用。

service的類型
  • ClusterIP 默認模式,只能在集羣內部訪問
  • NodePort 在每個節點上都監聽一個同樣的端口號(30000-32767),ClusterIP和路由規則會自動創建。集羣外部可以訪問:聯繫到集羣內部服務,可以配合外部負載均衡使用
  • LoadBalancer 要配合支持公有云負載均衡使用比如GCE、AWS。其實也是NodePort,只不過會把:自動添加到公有云的負載均衡當中
  • ExternalName 創建一個dns別名指到service name上,主要是防止service name發生變化,要配合dns插件使用
Node

節點(上圖橘色方框)是物理或者虛擬機器,作爲Kubernetes worker,通常稱爲Minion。每個節點都運行如下Kubernetes關鍵組件:

  • Kubelet:是主節點代理。
  • Kube-proxy:Service使用其將鏈接路由到Pod,如上文所述。
  • Docker或Rocket:Kubernetes使用的容器技術來創建容器。
Kubernetes Master

集羣擁有一個Kubernetes Master(紫色方框)。Kubernetes Master提供集羣的獨特視角,並且擁有一系列組件,比如Kubernetes API Server。API Server提供可以用來和集羣交互的REST端點。master節點包括用來創建和複製Pod的Replication Controller。

Deployment
  • Deployment:負責控制Pod的生命週期、保證服務有一定數量的Pod在運行。Deployment定義了Pod內容,包括Pod數量、更新方式、使用的鏡像,資源限制等等。
  • StatefulSet:管理應用程序的工作負載 API 對象,且該應用程序爲有狀態的應用程序。
  • DaemonSet:確保所有或部分節點上運行 Pod,例如日誌採集。
  • Job:一個 Job 創建一個或多個 Pod,直至運行結束。
  • CronJob:定時運行的 Job 任務。
Ingress

通常情況下,service和pod僅可在集羣內部網絡中通過IP地址訪問。所有到達邊界路由器的流量或被丟棄或被轉發到其他地方。從概念上講,可能像下面這樣:

internet --> service

Ingress是授權入站連接到達集羣服務的規則集合。

internet -->ingress --> service

你可以給Ingress配置提供外部可訪問的URL、負載均衡、SSL、基於名稱的虛擬主機等。用戶通過POST Ingress資源到API server的方式來請求ingress。 Ingress controller負責實現Ingress,通常使用負載平衡器,它還可以配置邊界路由和其他前端,這有助於以HA方式處理流量。
Ingress與騰訊雲的CLB類似,可以提供根據url進行轉發的功能,與Service最根本的區別就是Service不能根據url進行轉發只能定義端口轉發與負載方式如公網訪問,集羣內訪問等。兩者互補。
(K8S是使用IP tables的nat表進行轉發,騰訊針對IP tables在大併發情況下的性能差二次開發了IPVS)

NameSpace

對資源進行隔離,不同NameSpace空間的資源無法互相訪問,可不同業務分配不同的命名空間。
當團隊或項目中具有許多用戶時,可以考慮使用Namespace來區分,a如果是少量用戶集羣,可以不需要考慮使用Namespace,如果需要它們提供特殊性質時,可以開始使用Namespace。Namespace爲名稱提供了一個範圍。資源的Names在Namespace中具有唯一性。
Namespace是一種將集羣資源劃分爲多個用途(通過 resource quota)的方法。
在未來的Kubernetes版本中,默認情況下,相同Namespace中的對象將具有相同的訪問控制策略。對於稍微不同的資源沒必要使用多個Namespace來劃分,例如同意軟件的不同版本,可以使用labels(標籤)來區分同一Namespace中的資源。

Persistent Volumes(PV)

集羣內的存儲資源,例如節點是集羣的資源。PV 獨立於 Pod 的生命週期,根據不同的 StorageClass 類型創建不同類型的 PV。

Persistent Volume 簡稱PV是一個K8S資源對象,我們可以單獨創建一個PV。它不和Pod直接發生關係,而是通過Persistent Volume Claim,簡稱PVC來實現動態綁定。Pod定義裏指定的是PVC,然後PVC會根據Pod的要求去自動綁定合適的PV給Pod使用。

PersistentVolumeClaim(PVC)

PersistentVolumeClaim(PVC):集羣內的存儲請求。例如,PV 是 Pod 使用節點資源,PVC 則聲明使用 PV 資源。當 PV 資源不足時,PVC 也可以動態創建 PV。

服務的自動擴容算法

服務自動擴縮容後臺組件會定期(30s)向騰訊云云監控拉取容器和 POD 的監控指標,然後根據該指標當前值,當前副本數和該指標目標值計算出目標副本數,然後以該目標副本數作爲服務的期望副本數,達到自動伸縮的目的。 比如當前有 2 個實例, 平均 CPU 利用率爲 90%,服務自動伸縮設置目標 CPU 爲 60%, 則自動調整實例數量爲:90% * 2 / 60% = 3 個。如果用戶設置了多個彈性伸縮指標,HPA 會依據各個指標,分別計算出目標副本數,然後取最大的一個作爲最終目標副本數。—TKE文檔中心

Node的自動擴容

K8S核心組件

Kubernetes遵循master-slave architecture。Kubernetes的組件可以分爲管理單個的 node 組件和控制平面的一部分的組件。
Kubernetes Master是集羣的主要控制單元,用於管理其工作負載並指導整個系統的通信。Kubernetes控制平面由各自的進程組成,每個組件都可以在單個主節點上運行,也可以在支持high-availability clusters的多個主節點上運行。
Kubernetes主要由以下幾個核心組件組成:
在這裏插入圖片描述

核心組件結構圖
在這裏插入圖片描述
 除了核心組件,還有一些推薦的Add-ons:
在這裏插入圖片描述

實操篇

服務的自動擴容

自動擴容其實是K8S判斷POD的一些硬件指標(CPU使用率,帶寬等)是否達到了預警值,如果達到了,就行擴容,沒有到不變

命令行方式實現

kubectl autoscale deployment php-apache --min=1 --max=10 --cpu-percent=50

最小Pod數量爲1,最大爲10,當CPU使用率超過50%時觸發

yaml文件中指定
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1beta1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50
TKE 控制檯創建Deployment時指定

在這裏插入圖片描述

有狀態的服務如何通過deployment創建

鏡像的對接

1.先從docker hub上找到nginx 或tomcat指定版本的官方Dokcer file構建生成基礎鏡像,並推到私有倉庫中
基礎openresty鏡像例子:

# Dockerfile - alpine
# https://github.com/openresty/docker-openresty

ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.9"

FROM ${RESTY_IMAGE_BASE}:${RESTY_IMAGE_TAG}

LABEL maintainer="Evan Wies <[email protected]>"

# Docker Build Arguments
ARG RESTY_IMAGE_BASE="alpine"
ARG RESTY_IMAGE_TAG="3.9"
ARG RESTY_VERSION="1.15.8.1"
ARG RESTY_OPENSSL_VERSION="1.1.1c"
ARG RESTY_PCRE_VERSION="8.42"
ARG RESTY_J="1"
ARG RESTY_CONFIG_OPTIONS="\
    --with-compat \
    --with-file-aio \
    --with-http_addition_module \
    --with-http_auth_request_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_geoip_module=dynamic \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_image_filter_module=dynamic \
    --with-http_mp4_module \
    --with-http_random_index_module \
    --with-http_realip_module \
    --with-http_secure_link_module \
    --with-http_slice_module \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_sub_module \
    --with-http_v2_module \
    --with-http_xslt_module=dynamic \
    --with-ipv6 \
    --with-mail \
    --with-mail_ssl_module \
    --with-md5-asm \
    --with-pcre-jit \
    --with-sha1-asm \
    --with-stream \
    --with-stream_ssl_module \
    --with-threads \
    "
ARG RESTY_CONFIG_OPTIONS_MORE=""
ARG RESTY_LUAJIT_OPTIONS="--with-luajit-xcflags='-DLUAJIT_NUMMODE=2 -DLUAJIT_ENABLE_LUA52COMPAT'"

ARG RESTY_ADD_PACKAGE_BUILDDEPS=""
ARG RESTY_ADD_PACKAGE_RUNDEPS=""
ARG RESTY_EVAL_PRE_CONFIGURE=""
ARG RESTY_EVAL_POST_MAKE=""

# These are not intended to be user-specified
ARG _RESTY_CONFIG_DEPS="--with-openssl=/tmp/openssl-${RESTY_OPENSSL_VERSION} --with-pcre \
    --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include' \
    --with-ld-opt='-L/usr/local/openresty/pcre/lib -Wl,-rpath,/usr/local/openresty/pcre/lib' \
    "

LABEL resty_image_base="${RESTY_IMAGE_BASE}"
LABEL resty_image_tag="${RESTY_IMAGE_TAG}"
LABEL resty_version="${RESTY_VERSION}"
LABEL resty_openssl_version="${RESTY_OPENSSL_VERSION}"
LABEL resty_pcre_version="${RESTY_PCRE_VERSION}"
LABEL resty_config_options="${RESTY_CONFIG_OPTIONS}"
LABEL resty_config_options_more="${RESTY_CONFIG_OPTIONS_MORE}"
LABEL resty_config_deps="${_RESTY_CONFIG_DEPS}"
LABEL resty_add_package_builddeps="${RESTY_ADD_PACKAGE_BUILDDEPS}"
LABEL resty_add_package_rundeps="${RESTY_ADD_PACKAGE_RUNDEPS}"
LABEL resty_eval_pre_configure="${RESTY_EVAL_PRE_CONFIGURE}"
LABEL resty_eval_post_make="${RESTY_EVAL_POST_MAKE}"

# 1) Install apk dependencies
# 2) Download and untar OpenSSL, PCRE, and OpenResty
# 3) Build OpenResty
# 4) Cleanup

RUN apk add --no-cache --virtual .build-deps \
        build-base \
        coreutils \
        curl \
        gd-dev \
        geoip-dev \
        libxslt-dev \
        linux-headers \
        make \
        perl-dev \
        readline-dev \
        zlib-dev \
        ${RESTY_ADD_PACKAGE_BUILDDEPS} \
    && apk add --no-cache \
        bash \
        bash-doc \
        bash-completion \
        gd \
        geoip \
        libgcc \
        libxslt \
        zlib \
        ${RESTY_ADD_PACKAGE_RUNDEPS} \
    && cd /tmp \
    && if [ -n "${RESTY_EVAL_PRE_CONFIGURE}" ]; then eval $(echo ${RESTY_EVAL_PRE_CONFIGURE}); fi \
    && curl -fSL https://www.openssl.org/source/openssl-${RESTY_OPENSSL_VERSION}.tar.gz -o openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
    && tar xzf openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
    && curl -fSL https://ftp.pcre.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz \
    && tar xzf pcre-${RESTY_PCRE_VERSION}.tar.gz \
    && cd /tmp/pcre-${RESTY_PCRE_VERSION} \
    && ./configure \
        --prefix=/usr/local/openresty/pcre \
        --disable-cpp \
        --enable-jit \
        --enable-utf \
        --enable-unicode-properties \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install \
    && cd /tmp \
    && curl -fSL https://openresty.org/download/openresty-${RESTY_VERSION}.tar.gz -o openresty-${RESTY_VERSION}.tar.gz \
    && tar xzf openresty-${RESTY_VERSION}.tar.gz \
    && cd /tmp/openresty-${RESTY_VERSION} \
    && if [[ "1.1.1" == $(echo -e "${RESTY_OPENSSL_VERSION}\n1.1.1" | sort -V | head -n1) ]] ; then \
        echo 'patching Nginx for OpenSSL 1.1.1' \
        && cd bundle/nginx-1.15.8 \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.15.8-ssl_cert_cb_yield.patch | patch -p1 \
        && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/nginx-1.15.8-ssl_sess_cb_yield.patch | patch -p1 \
        && cd ../.. ; \
    fi \
    && eval ./configure -j${RESTY_J} ${_RESTY_CONFIG_DEPS} ${RESTY_CONFIG_OPTIONS} ${RESTY_CONFIG_OPTIONS_MORE} ${RESTY_LUAJIT_OPTIONS} \
    && make -j${RESTY_J} \
    && make -j${RESTY_J} install \
    && cd /tmp \
    && if [ -n "${RESTY_EVAL_POST_MAKE}" ]; then eval $(echo ${RESTY_EVAL_POST_MAKE}); fi \
    && rm -rf \
        openssl-${RESTY_OPENSSL_VERSION} \
        openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
        openresty-${RESTY_VERSION}.tar.gz openresty-${RESTY_VERSION} \
        pcre-${RESTY_PCRE_VERSION}.tar.gz pcre-${RESTY_PCRE_VERSION} \
    && apk del .build-deps \
    && ln -sf /dev/stdout /usr/local/openresty/nginx/logs/access.log \
    && ln -sf /dev/stderr /usr/local/openresty/nginx/logs/error.log

# Add additional binaries into PATH for convenience
ENV PATH=$PATH:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin:/bin/bash

# Copy nginx configuration files
COPY conf/nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY conf/nginx.conf /etc/nginx/conf.d/default.conf

#CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]
CMD ["bash"]
# Use SIGQUIT instead of default SIGTERM to cleanly drain requests
# See https://github.com/openresty/docker-openresty/blob/master/README.md#tips--pitfalls
STOPSIGNAL SIGQUIT

在這裏插入圖片描述
構建時使用docker build --tag 或構建完成後使用docker --tag imageid imagename:version

docker login url #登陸私有倉庫
docker tag 5787d71f774c shjrccr.ccs.tencentyun.com/yw/openresty:1.15.8.1-alpine-fat-apph5 #更改鏡像名稱
docker push shjrccr.ccs.tencentyun.com/yw /openresty:1.15.8.1-alpine-fat-apph5 #推送鏡像到私有倉庫

基於剛纔構建的openresty基礎鏡像,進行二次構建
業務nginx鏡像:

FROM  shjrccr.ccs.tencentyun.com/yw/openresty:1.15.8.1-alpine-fat

MAINTAINER WQ

ADD conf/nginx.conf /usr/local/openresty/nginx/conf/
RUN mkdir -pv  /app/public/view/ /app/logs
ADD pro/appH5 /app/public/view/

#CMD ["bash"]
CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]

將此業務鏡像推到私有倉庫即可
在這裏插入圖片描述

日誌的輸出與NFS類型的PV PVC

新建NFS服務器

安裝軟件包,啓動服務並添加至開機自啓

yum install -y rpcbind nfs-utils
systemctl start rpcbind
systemctl enable rpcbind
systemctl start nfs-server
systemctl enable nfs-server

修改配置文件,並重讀配置文件

[root@VM_1_11_centos ~]# cat /etc/exports
/opt/logs *(rw,sync,no_root_squash)
exportfs -r

命令行方式創建pv,pvc

TKE 控制檯無法直接創建nfs pv和nfs pvc可在創建deployment時選擇已有nfs

登陸任意Node節點,創建PV

[root@VM_1_14_centos k8s_test]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvnfs 50Gi RWO Retain Bound default/nfsclaim pvnfs 2d23h
[root@VM_1_14_centos k8s_test]# kubectl create -f pv_nfs.yaml

pv_nfs.yaml實例

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pvnfs
  namespace: default
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /opt/logs
    server: 10.2.1.11
  storageClassName: pvnfs
創建pvc

[root@VM_1_14_centos k8s_test]# kubectl create -f pvc_nfs.yaml
[root@VM_1_14_centos k8s_test]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfsclaim Bound pvnfs 50Gi RWO pvnfs 2d23h

pvc_nfs.yaml實例:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nfsclaim
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: pvnfs
創建deployment

[root@VM_1_14_centos k8s_test]# kubectl create -f nginx_deployment.yaml
[root@VM_1_14_centos k8s_test]# kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
lbapph5 3 3 3 3 2d22h

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-apph5
  labels:
    app: nginx-deployment-apph5
    vers: v02
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-deployment-apph5
      vers: v02
  template:
    metadata:
      labels:
        app: nginx-deployment-apph5
        vers: v02
    spec:
      containers:
      - image: shjrccr.ccs.tencentyun.com/yw/openresty:v1apph5v0.2
        imagePullPolicy: IfNotPresent
        name: apph5v02
        volumeMounts:
        - mountPath: "/app/logs/"
          name: nginx-nfs-pvc
      imagePullSecrets:
      - name: w-dr

      volumes:
      - name: nginx-nfs-pvc
        persistentVolumeClaim:
          claimName: nfsclaim

service的創建

[root@VM_1_14_centos k8s_test]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.16.255.1 443/TCP 6d23h
lbapph5 LoadBalancer 172.16.255.45 211.159.251.238 8000:30709/TCP 2d22h
[root@VM_1_14_centos k8s_test]# kubectl create -f service.yaml

實例:

apiVersion: v1
kind: Service
metadata:
  name: apph5-service
  labels:
    name: apph5-service
spec:
  type: NodePort      #這裏代表是NodePort類型的
  ports:
  - port: 80          #這裏的端口和clusterIP(10.97.114.36)對應,即10.97.114.36:80,供內部訪問。
    targetPort: 8000  #端口一定要和container暴露出來的端口對應,nodejs暴露出來的端口是8081,所以這裏也應是8081
    protocol: TCP
    nodePort: 32143   # 所有的節點都會開放此端口,此端口供外部調用。
  selector:
    app: nginx-deployment-apph5
    vers: v02

創建方式:

  • 可直接通過kuberctl create/apply -f servicename.yaml
  • 也可通過TKE控制面板創建
    在這裏插入圖片描述
service 與CLB綁定

service類型選擇NodePort,CLB綁定Node節點

在這裏插入圖片描述

登陸nfs服務器查看日誌

多個容器日誌會吐到同一文件
在這裏插入圖片描述

K8S相關角色配置文件示例

Node

有兩種創建方式:

  • 新增節點
  • 添加已有節點

在這裏插入圖片描述

Pod

實例:

apiVersion: v1
kind: Pod
metadata:
  name: apph5pod
spec:
  containers:
    - name: apph5pod
      image: shjrccr.ccs.tencentyun.com/yw/openresty:v1apph5v0.1
      imagePullPolicy: Always
  imagePullSecrets:
    - name: w-dr

在任意一臺Node上面通過命令kubectl 創建

kubectl [option] name
kubectl get podname -o wide/json/…

創建Pod以及查看:

[root@VM_1_14_centos k8s_test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
apph5pod 1/1 Running 0 15m
lbapph5-6bdbbb7ff5-fb7fq 1/1 Running 0 18m
lbapph5-6bdbbb7ff5-jzwbw 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-llnxs 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-qxmnp 1/1 Running 0 18m
[root@VM_1_14_centos k8s_test]# kubectl delete pod apph5pod
pod “apph5pod” deleted
[root@VM_1_14_centos k8s_test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
lbapph5-6bdbbb7ff5-fb7fq 1/1 Running 0 18m
lbapph5-6bdbbb7ff5-jzwbw 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-llnxs 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-qxmnp 1/1 Running 0 18m
[root@VM_1_14_centos k8s_test]# kubectl create -f pod.yaml
pod/apph5pod created
[root@VM_1_14_centos k8s_test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
apph5pod 1/1 Running 0 4s
lbapph5-6bdbbb7ff5-fb7fq 1/1 Running 0 18m
lbapph5-6bdbbb7ff5-jzwbw 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-llnxs 1/1 Running 0 4h13m
lbapph5-6bdbbb7ff5-qxmnp 1/1 Running 0 18m

PV

硬盤類型PV實例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nginx-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  qcloudCbs:
      cbsDiskId: disk-qlaxhjzq ## 指定已有的CBS id
      fsType: ext4
  storageClassName: cbs

NFS類型實例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pvnfs
  namespace: default
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /opt/logs
    server: 10.2.1.11
  storageClassName: pvnfs

accessModes:

  • ReadWriteOnce:數據卷能夠在一個節點上掛載爲讀寫目錄
  • ReadWriteMany:數據卷能夠在多個節點上掛載爲讀寫目錄
  • ReadOnlyMany: 數據卷能夠在多個節點上掛載爲讀寫目錄

PV回收策略:

  • Retain:PV釋放後,需要人工進行回收操作
    
  • Recycle:PV釋放後,K8S自動進行清理,清理成功後PV則可以在此綁定使用,目前只有NFS和HostPath類型的PV支持回收策略。當執行回收策略時,會創建一個PV Recycler Pod,這個Pod執行清理操作,即刪除PV目錄下的所有文件 含隱藏文件。

創建方式:

  • 可直接通過kuberctl create/apply -f pv.yaml
  • 也可以通過TKE控制檯創建,控制檯只能創建硬盤類型的PV
    在這裏插入圖片描述
POD

apiVersion: 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         //容器中的鏡像
    imagesPullPolicy: [Always|Never|IfNotPresent]//獲取鏡像的策略
    command: [String]     //容器的啓動命令列表(不配置的話使用鏡像內部的命令)
    args: [String]        //啓動參數列表
    workingDir: String    //容器的工作目錄
    volumeMounts:         //掛載到到容器內部的存儲卷設置
    - name: String
      mountPath: String
      readOnly: boolean
    ports:                //容器需要暴露的端口號列表
    - name: String
      containerPort: int  //容器要暴露的端口
      hostPort: int       //容器所在主機監聽的端口(容器暴露端口映射到宿主機的端口)
      protocol: String
    env:                  //容器運行前要設置的環境列表
    - name: String
      value: String
    resources:            //資源限制
      limits:
        cpu: Srting
        memory: String
      requeste:
        cpu: String
        memory: String
    livenessProbe:         //pod內容器健康檢查的設置
      exec:
        command: [String]
      httpGet:             //通過httpget檢查健康
        path: String
        port: number
        host: String
        scheme: Srtring
        httpHeaders:
        - name: Stirng
          value: String 
      tcpSocket:           //通過tcpSocket檢查健康
        port: number
      initialDelaySeconds: 0//首次檢查時間
      timeoutSeconds: 0     //檢查超時時間
      periodSeconds: 0      //檢查間隔時間
      successThreshold: 0
      failureThreshold: 0
      securityContext:      //安全配置
        privileged: falae
    restartPolicy: [Always|Never|OnFailure]//重啓策略
    nodeSelector: object    //節點選擇
    imagePullSecrets:
    - name: String
    hostNetwork: false      //是否使用主機網絡模式,默認否
  volumes:                  //在該pod上定義共享存儲卷
  - name: String
    meptyDir: {}
    hostPath:
      path: string
    secret:                 //類型爲secret的存儲卷
      secretName: String
      item:
      - key: String
        path: String
    configMap:             //類型爲configMap的存儲卷
      name: String
      items:
      - key: String
        path: String
健康檢測
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /demo/sql
            port: 9000
            scheme: HTTP
          initialDelaySeconds: 30
          periodSeconds: 30
          successThreshold: 1
          timeoutSeconds: 30
        name: sim-credit-auto
        readinessProbe:
          failureThreshold: 5
          httpGet:
            path: /demo/sql
            port: 9000
            scheme: HTTP
          initialDelaySeconds: 30
          periodSeconds: 30
          successThreshold: 1
          timeoutSeconds: 30
PVC

NFS-PV實例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-ali
  namespace: sim-bis
  labels:
    pv: pv-nfs-ali
spec:
  capacity:
    storage: 500Mi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /sim/bis/tomcat/ali
    server: 10.2.1.6
  storageClassName: sim-b-tomcat

指定pv的PVC實例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-ali
  namespace: sim-b
  labels:
    pv: pv-nfs-ali
spec:
  capacity:
    storage: 500Mi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /sim/bis/tomcat/ali
    server: 10.2.1.6
  storageClassName: sim-b-tomcat

創建方式:

  • 可直接通過kuberctl create/apply -f pvc.yaml
  • 也可通過TKE控制面板創建

在這裏插入圖片描述

Deployment

實例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dm-tomcat-auto
  labels:
    app: dm-tomcat-auto
    vers: v01
  namespace: sim-credit
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dm-tomcat-auto
      vers: v01
  template:
    metadata:
      labels:
        app: dm-tomcat-auto
        vers: v01
    spec:
      containers:
      - image: shjrccr.ccs.tencentyun.com/sim_credit/tomcat_base:v01
        imagePullPolicy: Always
        name: dm-tomcat-auto
        livenessProbe:
          httpGet:
            path: /demo/sql
            port: 9000
          #  host: localhost
            scheme: HTTP
          initialDelaySeconds: 90
          timeoutSeconds: 10
        volumeMounts:
        - mountPath: "/opt/apache-tomcat-8.5.14/webapps/"
          name: pvc-nfs-auto-war
        - mountPath: "/opt/apache-tomcat-8.5.14/logs/"
          name: pvc-nfs-auto-log
      imagePullSecrets:
      - name: qcloudregistrykey

      volumes:
      - name: pvc-nfs-auto-war
        persistentVolumeClaim:
          claimName: pvc-nfs-auto-war
      - name: pvc-nfs-auto-log
        persistentVolumeClaim:
          claimName: pvc-nfs-auto-log

創建方式:

  • 可直接通過kuberctl create/apply -f deploymentname.yaml
  • 也可通過TKE控制面板創建,控制面板創建會一起創建Service
    在這裏插入圖片描述
service
apiVersion: v1
kind: Service
metadata:
  name: apph5-service
  labels:
    name: apph5-service
spec:
  type: NodePort      #這裏代表是NodePort類型的
  ports:
  - port: 80          #這裏的端口和clusterIP(10.97.114.36)對應,即10.97.114.36:80,供內部訪問。
    targetPort: 8000  #端口一定要和container暴露出來的端口對應,nodejs暴露出來的端口是8081,所以這裏也應是8081
    protocol: TCP
    nodePort: 32143   # 所有的節點都會開放此端口,此端口供外部調用。
  selector:
    app: nginx-deployment-apph5
    vers: v02

Docker鏡像相關

鏡像對比
  • alpine 小巧,只有5M,依賴包較少
  • centos 200M左右,各種依賴包,字體等全
基礎鏡像
K8S命令

1、kubectl create -f nginx-deployment.yaml
2、查看deployment
kubectl get deployment
3、查看pod
kubectl get pod -o wide
4、測試pod訪問
curl --head 10.2.83.17
5、更新deployment
kubectl set image deployment/nginx-deployment nginx=nginx:v2 --record
6、查看更新後的deployment
kubectl get deployment -o wide
7、查看更新歷史
kubectl rollout history deployment/nginx-deployment
8、查看具體某一個版本的升級歷史
kubectl rollout history deployment/nginx-deployment --record
9、快速回滾到上一個版本
kubectl rollout undo deployment/nginx-deployment
10、擴容到5各節點
kubectl scale deployment nginx-deployment --replicas=5

在這裏插入圖片描述

私有倉庫命名

問題總結篇

PV-NFS創建時accessModes選擇Many,PVC綁定PV失敗,選擇Once後成功,也可讓多個Pod共享訪問,控制檯只能選擇硬盤PV 單臺讀寫

主要看後端存貯,模式一定要一致,用來吐日誌NFS有性能瓶頸,推薦file beat,壓測NFS性能,容器標準輸出到宿主機,

service 綁定deployment時,label選擇不正確或少了,導致綁定不成功,訪問空白

service 對應Deployment的label
發佈藍鯨調用TKE的API
用NFS方式的war包 TKE一些特性無法實現
本地push鏡像到TKE鏡像倉庫 網速波動

deployment pod的labels 與deployment的labels必須相同
ingress本質就是clb,創建ingress會自動創建一個clb

應用型CLB有url匹配
service ingress 4層7層

pv一旦被pvc綁定後,就被該pvc獨佔,不能在與其他pvc綁定
pod 減少的時候會不會等待pod內的請求處理完成!

優雅關閉優雅關閉是指在pod準備關閉時,可能還需要做一些處理,比如保存數據等。這期間服務不會接受新的請求。kubernetes提供了優雅關閉的配置terminationGracePeriodSeconds: 60
在給pod發出關閉指令時,k8s將會給應用發送SIGTERM信號,程序只需要捕獲SIGTERM信號並做相應處理即可。配置爲k8s會等待60秒後關閉。
docker鏡像的 STOPSIGNAL SIGQUIT
超過等待時間直接強制殺死POD

業務的代碼放在NFS中,更新重啓pod即可,鏡像在配置文件變更時在pull!

根據不同的路徑區分不同的版本

tomcat更改war包和解壓文件放到不同目錄!
pod的自動擴容頻率的間隔時長?

第一次擴 達到即擴容,兩次擴的間隔5分鐘,兩次收縮間隔3分鐘
秒殺活動不現實

pod的自動擴容數量爲現有pod的2倍,TKE是否同樣限制?是否可配置
突然過高併發流量導致pod阻塞,健康檢查無法通過導致服務崩潰?

初始pod數量調高 提高系統整體吞吐量,初始pod佔用資源調高 提升單個pod的可承受併發量

service對pod的負載規則?能否設置?權重,輪詢

輪詢

超出指定pod數量的pod實列多長時間會刪除和回收?

8個總量,實際佔用request的值

Terminating狀態的pod會如何處理?時長?

強制刪除pod
kubectl delete pod podname --force --grace-period 0 -n namespace
容器內有非空目錄(容器運行過程中) 其他情況

node的調度局部最優解和全局最優解:1.12版本後默認未局部最優解

千臺node不會出現調度器瓶頸

設置pod的自動擴容的實例數量範圍後,pod的數量並未自動擴容到範圍的下限數量
容器服務的概覽中的集羣資源使用量至少需要保持在30%~40%的可用率

此處的資源使用量計算:如果node的內存還剩0.5G 內存0.5G,這樣的node有4臺,會在資源使用量中生成2G CPU 2G內存,但pod請求的資源某一項超過0.5G則pod不會創建成功,會造成對pod數量的錯誤計算

健康檢測中就緒檢測只在容器初始化時檢測一次?

在壓測時未配置健康檢測,只配置了就緒檢測,但部分pod發現會重啓導致本來就承受不住併發流量的服務崩潰
有檢測時間間隔
健康檢查失敗 重啓,存活檢查失敗 流量不進入

server的Selectors只匹配到deployment不匹配pod?

因通過控制檯生成的deployment的label和pod的label相同
label匹配

hpa間隔60S獲取一次pod的擴容指標,2~3分鐘後擴容的pod恢復到最小數量
hpa獲取擴容指標時,有時會並不準確,關閉壓測了,並且hpa值已經下降,但下一分鐘的hpa值又飆升

在這裏插入圖片描述

待確定

多個應用放到同一個集羣,namespace隔離
CLB目前只能綁定主機
新增NODE,已有POD只等待下次調度,新的POD會分配到新的NODE
海通證券,QQ空間 微視 騰訊視頻
非核心交易都已容器化(兩年前),秒殺F5限流
前期規劃 容器給一個B端
pod同樣受所在NODE的安全組限制
日誌是filebeat 還是NFS

相關資料地址和網站

Docker官網
DockerHub官網
Kubernetes官網
Kubernetes中文文檔
十分鐘帶你理解Kubernetes核心概念
Kubernetes 編排系統
Docker與虛擬機的簡介以及比較

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章