k8s入門你至少需要會哪些

俞正東發表於2021-08-07

前言

相信很多公司都有整合釋出pass系統,底層大多數依賴於k8s來進行服務的釋出部署/回滾等功能。
對於很多業務開發者都是不可見的,在感嘆這個東西真好用的同時,想著探一探這背後的原理。

真正的入門還是得自己親手跑起來!

今天這篇k8s入門我整理了必會的幾個k8s知識點

  • docker的使用,映象的建立和釋出(我當你已經會了哈)
  • k8s開發環境搭建
  • Deployment的使用
  • Service的使用
  • ConfigMap的使用

學習環境搭建

首先k8s學習的話是建議用minikube搭建,這裡系統我用的ubuntu20.04.2.0LTS

image

我這裡用的是vmware虛擬機器,
如果FQ不順利的話請加我微信獲取已經裝好環境的虛擬機器(節省你時間不香嗎),前提你的機器得是32G記憶體或以上

image

假設你自己裝了,或者你用了我的vmware虛擬機器,或者你用docker Desktop裝的k8s,那麼啟動後

敲命令來啟動minikube:

minikube start

image

耐心等待完成後使用 minikube status 檢視狀態是否是Running:

image

然後我們要啟動k8s控制皮膚-dashbord服務,下面的命令裡 —url 的意思是啟動後,列印dashbord的url。不帶的話會啟動你本機瀏覽器開啟。

minikube dashboard --url

image

k8s的控制皮膚預設的是本機(localhost)才能開啟,所以需要使用k8s的proxy功能,到虛擬機器的terminal視窗敲入以下命令:


kubectl proxy --port=8001 --address=0.0.0.0 --accept-hosts='^.*'

image

由於是虛擬機器環境,只能是虛擬機器所在的機器才能開啟 需要做虛擬機器埠對映,
本虛擬機器的請忽略此步驟!

image

image

做了本機埠到虛擬機器的埠對映之後,

開啟你本機瀏覽器直接訪問虛擬機器的k8s的控制皮膚

注意我上面用的k8s proxy是8001埠,url如下:

http://<本機IP>:8001/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/#/service?namespace=default

開啟如下圖:

image

寫一個demo應用然後部署到k8s

demo就是一個自帶的的天氣預報的webapi模板。

然後建立成功後 需要更改一處程式碼(看註釋):


[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}

[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
//這裡加下獲取本機ip,因為到時候部署到k8s我們得確認是不是訪問的ip會變化
var feature = HttpContext.Features.Get<IHttpConnectionFeature>();
string LocalIPAddr = feature?.LocalIpAddress?.ToString() ?? "unknow";

var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
//到時候候我們確認這個欄位即可
Summary = LocalIPAddr
})
.ToArray();
}
}

然後把這個demo應用建立一個映象並推送到dockerhub倉庫,

這裡我使用我的開源工具AntDeploy來一鍵推送。

image

這個工具使用教程可以檢視我之前寫的

[開源]製作docker映象不依賴linux和Docker環境

工具的背後原理可以檢視:

Docker映象構建原理解析(不裝docker也能構建映象)

我把這個demo傳到了dokcerHub映象的地址:nainaigu/k8s-demo:1.8

1. Deployment的使用

Deployment的作用是定義及管理多副本應用(即多個副本 Pod)

如果Pod出現故障,對應的服務也會掛掉,所以Kubernetes提供了一個Deployment的概念,
目的是讓Kubernetes去管理一組Pod的副本,也就是副本集,
這樣就能夠保證一定數量的副本一直可用,不會因為某一個Pod掛掉導致整個服務掛掉。

編寫Deployment的yml檔案


apiVersion: apps/v1 // 指定版本,支援的版本可以通過kubectl api-versions查詢
kind: Deployment //固定 指定型別,這一次我們要建立一個Deployment
metadata: #後設資料
name: k8s-demo //delpoyment的名稱,必須在deployment中保持唯一
labels:
name: k8s-demo //反正所有標籤都一個名字
spec: //deployment的詳細內容
replicas: 2 //容器2個副本pod
selector: //選擇器
matchLabels:
name: k8s-demo //選擇label中的name=k8s-demo的
template:
metadata:
labels:
name: k8s-demo //指定一個label名為name,值為k8s-demo,對應上面的selector
spec:
containers:
- name: k8s-demo //容器名
image: nainaigu/k8s-demo:1.8 //映象地址
imagePullPolicy: IfNotPresent //如果本地沒有映象就去倉庫pull
ports:
- containerPort: 5000 //容器暴露的埠
env: //環境變數
- name: "ASPNETCORE_URLS"
value: "http://0.0.0.0:5000"

上面的配置的意思就是:

  • 從映象倉庫拉取你的映象
  • 配置你的映象啟動的引數,暴露的埠等
  • 給你這個服務起個名字並且打上標籤,執行後會有2個pod(服務例項)

接下來把這個配置儲存為k8s-demo.yml 上傳到虛擬機器然後敲命令裝配到k8s

//建立
kubectl create -f k8s-demo.yaml

//檢視,後面想看某個pod的啟動日誌 也需要先找到pod名稱
kubectl get pod -l name=k8s-demo

image

然後在k8s皮膚上檢視

image

2. Service的使用和建立

k8s Service定義了這樣一種抽象: Service是一種可以訪問 Pod邏輯分組的策略, Service通常是通過 Label Selector訪問 Pod組(等下在寫service的yml檔案就能看出來了)

Service的出現,可以解決每次Deployment的時候ip會換的問題

不過Service只支援4層的負載均衡,不支援7層(k8s是用Ingress來支援7層)。

當Pod當機後重新生成時,其IP等狀態資訊可能會變動,
Service會根據Pod的Label對這些狀態資訊進行監控和變更,保證上游服務不受Pod的變動而影響

Service在 K8s中有常見的以下幾種型別:

  • ClusterIp <只能是叢集內部訪問,可以通過proxy讓外部訪問>
  • NodePort <nodeport來暴露服務讓外部訪問>
  • LoadBalancer <生產環境一般都是使用LoadBalancer的方式>

apiVersion: v1
kind: Service
metadata:
name: k8s-demo
spec:
selector: //篩選pod。上面建立Deployment的時候指定了
name: k8s-demo
type: ClusterIP //只能k8s叢集內部訪問,外部網路不能夠訪問到
ports:
- protocol: TCP
port: 5000 //k8s叢集內部通過 5000 埠來訪問 下面的
targetPort: 5000 //容器暴露埠,與Dockerfile暴露埠保持一致

上面的Service配置表示:

  • 建立了一個名叫k8s-demo的Service
  • 用來訪問上面我們Deployment建立的一組name=k8s-demo的Pods
  • 不管你Deployment後面是重新發布還是擴容還是縮容,不管怎麼變化,只要通過Service暴露的埠就能負載均衡的訪問到那一組 Pods
  • 我們設定的型別是ClusterIP,預設是k8s叢集內部可訪問,但是也可以通過k8s的proxy功能來訪問

如果是NodePort(可以叢集外訪問)的話要需要按照如下規則來配置


apiVersion: v1
kind: Service
metadata:
name: k8s-demo
spec:
selector: //篩選pod。上面建立Deployment的時候指定了
name: k8s-demo
type: NodePort //配置為NodePort,外部可以訪問,要定義下面的nodePort引數
ports:
- protocol: TCP
port: 5000 //k8s叢集內部通過 5000 埠來訪問 下面的
targetPort: 5000 //容器暴露埠,與Dockerfile暴露埠保持一致
nodePort: 30001 // NodePort,外部訪問的埠來訪問上面的targetPort

總結這2種的區別就是:

叢集內 serviceip:容器埠。 叢集外: 宿主機IP:nodePort埠

我們按照第一種方式(type: ClusterIP)測試

image

檢視下service的ip:10.105.108.92

image

由於是叢集內部才能訪問,所以先用下面的命令進入minikube搭建的k8s叢集內部環境


minikube ssh

curl http://10.105.108.92:5000/WeatherForecast

image

訪問服務成功!!

在外部網路可以使用k8s的proxy來訪問


http://10.32.104.164:8001/api/v1/namespaces/default/services/k8s-demo:5000/proxy/WeatherForecast

注意通過proxy訪問的url拼接的規範:

  • k8s-demo:5000 代表你建立的service的名稱和埠
  • /WeatherForecast 代表你服務暴露的介面

image

ConfigMap的使用

ConfigMap 就是為了讓映象 和 配置檔案解耦。好比一個動態的資料來源,你建立後可以在
建立Deployment的時候指定用它。然後你想要動態更新,容器內也能監聽到檔案內容更改,進行熱過載!

k8s的另外一個類似的功能叫secret,Secret類似於ConfigMap,是用Base64加密,密文顯示,一般存放敏感資料!

下面建立一個appsettings.json的configMap


apiVersion: v1
kind: ConfigMap
metadata:
name: appsettings
data:
appsettings.json: |-
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Settings": {
"Message": "The configuration is working!"
}
}

然後改下demo應用

image

這裡單獨搞了一個Settings的目錄來儲存配置檔案。

image

然後在api裡面讀出來配置的Settings.Message資訊

image

這裡注意有一個坑 :netcore中的預設的機制是監聽配置檔案的lastChangetime,
但是configMap變更後居然不會有任何變化(因為它是符號連線(symbolic link)),所以需要自己寫一個watch來適配,詳細可以看demo中的程式碼!

下面來測試下效果:

第一步:把configMap建立到k8s中

第二步:先刪除掉上面建立的Deployment和Service

第三步:在Deployment的配置中用configMap

第四步:重新建立Deployment和Service

以上四步可以一次性搞定,
k8s的yml可以把Deployment和Service和configMap全放在一個yml檔案:


apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-demo
labels:
name: k8s-demo
spec:
replicas: 2
selector:
matchLabels:
name: k8s-demo
template:
metadata:
labels:
name: k8s-demo
spec:
containers:
- name: k8s-demo
image: nainaigu/k8s-demo:1.8
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
env:
- name: "ASPNETCORE_URLS"
value: "http://0.0.0.0:5000"
volumeMounts:
- name: appsettings-volume
mountPath: "/publish/Settings" //這裡用configMap
volumes:
- name: appsettings-volume
configMap:
name: appsettings //這裡用configMap

---

apiVersion: v1
kind: Service
metadata:
name: k8s-demo
spec:
selector:
name: k8s-demo
type: ClusterIP
ports:
- protocol: TCP
port: 5000
targetPort: 5000

---

apiVersion: v1
kind: ConfigMap
metadata:
name: appsettings
data:
appsettings.json: |-
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Settings": {
"Message": "The configuration is working!"
}
}

image

如上圖,一個yml建立了configMap,Service,Deployment。

建立完成後,看下k8s皮膚:

image

通過proxy訪問下我們的demo服務:

image

由於我們在Deployment指定replicas:2個pod,訪問服務會負載均衡,ip會切換。

配置讀取的configmap資訊是預設的 “The configuration is working!”

下面我們動態修改下configMap,來測試下demo應用會不會重新載入!

image

image

然後在來訪問下demo服務

image

確實載入到了新的配置了!

補充一些常用的命令:

檢視部署的歷史記錄:

kubectl rollout history deployment.apps/k8s-demo
image

回滾 :kubectl rollout undo
比如回滾到上一個:

kubectl rollout undo deploy/k8s-demo

回滾到指定的版本:

kubectl rollout undo deploy/k8s-demo —to-revision=2 

指定的版本可以通過歷史記錄的Revision欄位

擴縮容kubectl scale

kubectl scale deployment k8s-demo —replicas=2

也可以在皮膚上操作

把2個例項 擴容到3個例項:

image

也可以設定達到某個條件自動擴容:

kubectl autoscale deployment k8s-demo —min=10 —max=20 —cpu-precent=70

代表最低10個例項,一旦cpu超過70% 自動觸發擴容 最大擴容到20個例項

檢視Deployment的容器啟動日誌 kubectl logs

image

demo應用的原始碼:
https://github.com/yuzd/envoytest

 

 

 

相關文章