千里之行,始於足下
當我們新學習一門程式語言時,總是從 hello, world
開始。
當我們學習如何在 k8s 上部署應用時,部署一個簡單的 nginx
,能夠訪問到它的配置頁面。由於它五臟俱全,功能簡單,無狀態,可以當做 k8s 部署應用的 hello, world
。
本篇文章將學習如何使用 Pod
,Deployment
與 Service
開始部署第一個應用
- 本文地址: 使用 k8s 部署你的第一個應用
- 系列文章: 個人伺服器運維指南
如果對你能夠有所幫助,可以幫我在 shfshanyue/op-note 上點個 star。
Pod
pod
是 kubernetes
中最小的編排單位,通常由一個容器組成 (有時候會有多個容器組成)。
以下是一個 pod 資源配置檔案的最小示例,關於詳細配置參考 kubernetes v1.16 Pod
我們使用 nginx:alpine
作為映象部署了一個 Pod
,並且暴露了 80 埠
apiVersion: v1
kind: Pod
metadata:
name: nginx
# 指定 label,便於檢索
labels:
app: nginx
spec:
containers:
- name: nginx
# 指定映象
image: nginx:alpine
# 指定暴露埠
ports:
- containerPort: 80
複製程式碼
使用 kubectly apply
,部署 Pod
$ kubectl apply -f nginx.yaml
pod/nginx created
複製程式碼
校驗部署狀態,此時 STATUS 為 Running
表明部署成功
# 獲取 Pod 部署的狀態,特別是 IP
# -o wide 列出IP/Node等更多資訊
$ kubectl get pods nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 14m 10.244.1.9 shuifeng <none> <none>
複製程式碼
使用 -o wide
獲取到 pod 的 IP 地址,訪問該 IP 檢視是否能夠訪問到 nginx
經典的配置頁面
# 獲取更加詳細的資訊
$ kubectl describe pod nginx
# 每個 pod 都有一個IP地址,直接訪問IP地址獲取內容
$ curl 10.244.1.9
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
複製程式碼
此時我們可以使用 kubectl exec
進入 Pod
的內部容器。如果 Pod
中有多個容器,使用 kubectl exec -c
指定容器
$ kubectl exec -it nginx sh
複製程式碼
在 Pod
容器中執行命令,校驗其中的 socket
情況以及 nginx 服務
# 在 POD 中執行命令
# 可以看到 nginx 起的80埠
$ netstat -tan
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
# 訪問 nginx,正確返回配置頁面的內容
# -q: 不輸出 wget 自身資訊
# -O -: 定向到標準輸出
$ wget -q -O - localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
複製程式碼
Deployment
在 k8s
中編排應用可以更好地做彈性擴容,負載均衡。既然要均衡,一個 Pod 肯定不能均衡,自然要部署多個 Pod
docker-compose
可以簡單地通過 docker-compose scale
來擴容,k8s
更不在話下了。
在k8s中管理 Pod
的稱作 Controller
,我們可以使用 Deployment
這種 Controller
來為 Pod
進行擴容,當然它還可以滾動升級,回滾,金絲雀等等關於部署的事情
我們編寫一個 Deployment
的資源配置檔案
spec.template
: 指定要部署的 Podspec.replicas
: 指定要部署的個數spec.selector
: 定位需要管理的 Pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
複製程式碼
我們使用 kubectl apply
部署生效後檢視 Pod
以及 Deployment
狀態
$ kubectl apply -f nginx.yaml
# nginx-deployment 部署的三個 pod 全部成功
$ kubectl get pods -o wide -l 'app=nginx'
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 1 4h29m 10.244.1.9 shuifeng <none> <none>
nginx-deployment-54f57cf6bf-57g8l 1/1 Running 0 23m 10.244.1.10 shuifeng <none> <none>
nginx-deployment-54f57cf6bf-ltdf7 1/1 Running 0 23m 10.244.1.11 shuifeng <none> <none>
nginx-deployment-54f57cf6bf-n8ppt 1/1 Running 0 23m 10.244.1.12 shuifeng <none> <none>
# READY 3/3 表明全部部署成功
$ kubectl get deploy nginx-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 23m
複製程式碼
Service
現在我們已經部署了一個 Deployment,其中有三個 Pod,就有三個 IP,那我們如何向這三個 Pod 請求服務呢,何況每當上線部署後,就會產生新的 Pod IP。即我們如何做服務發現
我們可以通過 Service
解決這個問題,做指定 Deployment
或者特定集合 Pod
的網路層抽象
配置檔案如下
spec.selector
: 指定如何選擇Pod
spec.ports
: 指定如何暴露埠
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
複製程式碼
我們使用 kubectl apply
部署生效後檢視 Service
狀態
$ kubectl get svc nginx-service -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-service ClusterIP 10.108.9.49 <none> 80/TCP 11m app=nginx
複製程式碼
ClusterIP
代表服務只能在叢集內部訪問,此時我們訪問 10.108.9.49
訪問服務
$ curl 10.108.9.49
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
複製程式碼
服務發現,我們只需要知道服務的名字便能夠訪問服務,只能通過 IP 訪問也太 low 了。Service
當然不會這麼 low
在 k8s 中,所有的服務可以通過 my-svc.my-namespace.svc.cluster.local
做服務發現,對於剛才部署的 Service 就是 nginx-service.default.svc.cluster.local
在叢集中的任意一個 Pod 中通過域名訪問服務,訪問成功
$ curl nginx-service.default.svc.cluster.local
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
複製程式碼
小結
通過配置 Deployment
與 Service
,此時我們可以在叢集中通過服務發現訪問域名。完整的配置檔案如下
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
複製程式碼
當我們仍然需要把服務暴露給網際網路,那我們如何在叢集外訪問域名呢?
關注公眾號
歡迎關注公眾號山月行,我會定期分享一些前後端以及運維的文章,並且會有技術與生活上的每日回顧與總結,歡迎關注交流