| 知乎專欄 | 多維度架構 | 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者” |
apiVersion: v1 kind: ServiceAccount metadata: labels: app: elasticsearch name: elasticsearch namespace: elastic
創建 jenkins-namespace.yaml
apiVersion: v1 kind: Namespace metadata: name: jenkins-project
$ kubectl create -f jenkins-namespace.yaml namespace ”jenkins-project“ created
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox
args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
iMac:kubernetes neo$ kubectl create -f pod.yaml pod/counter created iMac:kubernetes neo$ kubectl logs counter 0: Sun Oct 4 12:32:44 UTC 2020 1: Sun Oct 4 12:32:45 UTC 2020 2: Sun Oct 4 12:32:46 UTC 2020 3: Sun Oct 4 12:32:47 UTC 2020 4: Sun Oct 4 12:32:48 UTC 2020 5: Sun Oct 4 12:32:49 UTC 2020 6: Sun Oct 4 12:32:50 UTC 2020 7: Sun Oct 4 12:32:51 UTC 2020 8: Sun Oct 4 12:32:52 UTC 2020 9: Sun Oct 4 12:32:53 UTC 2020
apiVersion: v1
kind: Pod
metadata:
name: hostaliases-pod
spec:
restartPolicy: Never
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "foo.local"
- "bar.local"
- ip: "10.1.2.3"
hostnames:
- "foo.remote"
- "bar.remote"
containers:
- name: cat-hosts
image: busybox
command:
- cat
args:
- "/etc/hosts"
apiVersion: v1
kind: Pod
metadata:
name: envars-fieldref
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv NODE_NAME POD_NAME POD_NAMESPACE;
printenv POD_IP POD_SERVICE_ACCOUNT;
sleep 10;
done;
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: POD_SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
restartPolicy: Never
apiVersion: v1
kind: Pod
metadata:
name: envars-resourcefieldref
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox:1.24
command: [ "sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv CPU_REQUEST CPU_LIMIT;
printenv MEM_REQUEST MEM_LIMIT;
sleep 10;
done;
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "64Mi"
cpu: "250m"
env:
- name: CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.cpu
- name: CPU_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.cpu
- name: MEM_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.memory
- name: MEM_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.memory
restartPolicy: Never
就緒探針
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10 #10s之後開始第一次探測
periodSeconds: 5 #第一次探測之後每隔5s探測一次
kubelet --allowed-unsafe-sysctls \ 'kernel.msg*,net.core.somaxconn' ...
apiVersion: v1
kind: Pod
metadata:
name: sysctl-example
spec:
securityContext:
sysctls:
- name: kernel.shm_rmid_forced
value: "0"
- name: net.core.somaxconn
value: "1024"
- name: kernel.msgmax
value: "65536"
allowPrivilegeEscalation 表示是否繼承父進程權限,runAsUser 表示使用 UID 1000 的用戶運行
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
containers:
- name: sec-ctx-demo
image: busybox:latest
securityContext:
runAsUser: 1000
allowPrivilegeEscalation: false
security.alpha.kubernetes.io/sysctls
apiVersion: v1
kind: Pod
metadata:
name: sysctl-example
annotations:
security.alpha.kubernetes.io/sysctls: kernel.shm_rmid_forced=1
spec:
unsafe-sysctls
apiVersion: v1
kind: Pod
metadata:
name: sysctl-example
annotations:
security.alpha.kubernetes.io/unsafe-sysctls: net.core.somaxconn=65535 #使用unsafe sysctl,設置最大連接數
spec:
securityContext:
privileged: true #開啟privileged權限
創建 service.yaml 檔案
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
- name: https
protocol: TCP
port: 443
targetPort: 443
iMac:kubernetes neo$ kubectl create -f service.yaml service/my-service created
查看服務
iMac:kubernetes neo$ kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 113m my-service ClusterIP 10.106.157.143 <none> 80/TCP,443/TCP 64s
查看 service 後端代理的 pod 的 ip,這裡沒有掛載 pod 所以顯示 none
iMac:kubernetes neo$ kubectl get endpoints my-service NAME ENDPOINTS AGE my-service <none> 2m20s
報漏 80.11.12.10:80 地址
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
apiVersion: v1 kind: Service metadata: name: my-service namespace: prod spec: type: ExternalName externalName: my.database.example.com
apiVersion: v1
kind: Service
metadata:
name: spring-cloud-config-server
namespace: default
labels:
app: springboot
spec:
#type: NodePort
ports: web
- port: 8888
targetPort: web
clusterIP: 10.10.0.1
selector:
app: spring-cloud-config-server
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: MyApp
ports:
# By default and for convenience, the `targetPort` is set to the same value as the `port` field.
- port: 80
targetPort: 80
# Optional field
# By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
nodePort: 30007
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
apiVersion: v1
kind: Service
metadata:
name: registry
namespace: default
labels:
app: registry
spec:
type: NodePort
selector:
app: registry
ports:
- name: registry
port: 5000
nodePort: 30050
protocol: TCP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
namespace: default
labels:
app: registry
spec:
replicas: 1
selector:
matchLabels:
app: registry
template:
metadata:
labels:
app: registry
spec:
containers:
- name: registry
image: registry:latest
resources:
limits:
cpu: 100m
memory: 100Mi
env:
- name: REGISTRY_HTTP_ADDR
value: :5000
- name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
value: /var/lib/registry
ports:
- containerPort: 5000
name: registry
protocol: TCP
apiVersion: v1 kind: ConfigMap metadata: name: db-config namespace: default data: db.host: 172.16.0.10 db.port: '3306' db.user: neo db.pass: chen
創建配置
neo@MacBook-Pro-Neo ~/tmp/kubernetes % kubectl create -f key-value.yaml configmap/db-config created
將配置項保存到檔案
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh", "-c", "cat /usr/local/etc/config/db.host" ]
volumeMounts:
- name: config-volume
mountPath: /usr/local/etc/config
volumes:
- name: config-volume
configMap:
name: db-config
restartPolicy: Never
定義多組配置項
apiVersion: v1
kind: ConfigMap
metadata:
name: spring-cloud-config
namespace: default
data:
config: |
spring.security.user=config
spring.security.user=passw0rd
euerka: |
spring.security.user=eureka
spring.security.user=passw0rd
gateway: |
spring.security.user=gateway
spring.security.user=passw0rd
envFrom 可將 ConfigMap 中的配置項定義為容器環境變數
apiVersion: v1
kind: Pod
metadata:
name: neo-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: special-config
restartPolicy: Never
引用單個配置項使用 valueFrom
neo@MacBook-Pro-Neo ~/tmp/kubernetes % cat key-value.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: db-config
namespace: default
data:
db.host: 172.16.0.10
db.port: '3306'
db.user: neo
db.pass: chen
---
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-container
image: busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: DBHOST
valueFrom:
configMapKeyRef:
name: db-config
key: db.host
- name: DBPORT
valueFrom:
configMapKeyRef:
name: db-config
key: db.port
restartPolicy: Never
neo@MacBook-Pro-Neo ~/tmp/kubernetes % kubectl create -f key-value.yaml
configmap/db-config created
pod/test-pod created
定義配置
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
labels:
app: redis
data:
redis.conf: |-
pidfile /var/lib/redis/redis.pid
dir /var/lib/redis
port 6379
bind 0.0.0.0
appendonly yes
protected-mode no
requirepass 123456
引用配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
labels:
app: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:5.0.8
command:
- "sh"
- "-c"
- "redis-server /usr/local/etc/redis/redis.conf"
ports:
- containerPort: 6379
resources:
limits:
cpu: 1000m
memory: 1024Mi
requests:
cpu: 1000m
memory: 1024Mi
livenessProbe:
tcpSocket:
port: 6379
initialDelaySeconds: 300
timeoutSeconds: 1
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
readinessProbe:
tcpSocket:
port: 6379
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
volumeMounts:
- name: data
mountPath: /data
- name: config
mountPath: /usr/local/etc/redis/redis.conf
subPath: redis.conf
volumes:
- name: data
persistentVolumeClaim:
claimName: redis
- name: config
configMap:
name: redis-config
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh","-c","find /etc/config/" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: special.how
path: path/to/special-key
restartPolicy: Never
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
spec:
capacity:
storage: 100Gi
# volumeMode field requires BlockVolume Alpha feature gate to be enabled.
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- example-node
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-volume
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: netkiller-local-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-volume
local:
path: /tmp/neo
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- minikube
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: netkiller-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: local-volume
---
kind: Pod
apiVersion: v1
metadata:
name: busybox
namespace: default
spec:
containers:
- name: busybox
image: busybox:latest
# image: registry.netkiller.cn:5000/netkiller/welcome:latest
imagePullPolicy: IfNotPresent
command:
- sleep
- "3600"
volumeMounts:
- mountPath: "/srv"
name: mypd
restartPolicy: Always
volumes:
- name: mypd
persistentVolumeClaim:
claimName: netkiller-pvc
部署 POD
iMac:kubernetes neo$ kubectl create -f example/volume/local.yaml storageclass.storage.k8s.io/local-volume created persistentvolume/netkiller-local-pv created persistentvolumeclaim/netkiller-pvc created pod/busybox created
查看POD狀態
iMac:kubernetes neo$ kubectl get pod NAME READY STATUS RESTARTS AGE busybox 1/1 Running 0 2m28s
進入POD查看local卷的掛載情況,同時創建一個測試檔案。
iMac:kubernetes neo$ kubectl exec -it busybox sh kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. / # mount | grep /srv tmpfs on /srv type tmpfs (rw) / # echo helloworld > /srv/netkiller / # cat /srv/netkiller helloworld
進入宿主主機查看掛載目錄
$ cat /tmp/neo/netkiller helloworld
.spec.completions 標誌Job結束需要成功運行的Pod個數,預設為1
.spec.parallelism 標誌並行運行的Pod的個數,預設為1
.spec.activeDeadlineSeconds 標誌失敗Pod的重試最大時間,超過這個時間不會繼續重試
apiVersion: batch/v1
kind: Job
metadata:
name: busybox
spec:
completions: 1
parallelism: 1
template:
metadata:
name: busybox
spec:
containers:
- name: busybox
image: busybox
command: ["echo", "hello"]
restartPolicy: Never
$ kubectl create -f job.yaml
job "busybox" created
$ pods=$(kubectl get pods --selector=job-name=busybox --output=jsonpath={.items..metadata.name})
$ kubectl logs $pods
.spec.schedule 指定任務運行周期,格式同Cron
.spec.startingDeadlineSeconds 指定任務開始的截止期限
.spec.concurrencyPolicy 指定任務的並發策略,支持Allow、Forbid和Replace三個選項
apiVersion: batch/v2alpha1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
正常情況 Service 只是暴露了連接埠,這個連接埠是可以對外訪問的,但是80連接埠只有一個,很多 Service 都要使用 80連接埠,這時就需要使用虛擬主機技術。
多個 Service 共同使用一個 80 連接埠,通過域名區分業務。這就是 Ingress 存在的意義。
+----------+ Ingress +---------+ Pod +----------+ | internet | ---------> | Service | --------> | Pod Node | +----------+ +---------+ +----------+
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: springboot
spec:
backend:
service:
name: springboot
port:
number: 80
Ingress / ---> /api --> api-service:8080
www.netkiller.cn ---------> | ---> /usr --> usr-service:8080
\ ---> /img --> img-service:8080
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: uri-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: www.netkiller.cn
http:
paths:
- path: /api
backend:
serviceName: api-service
servicePort: 8080
- path: /usr
backend:
serviceName: usr-service
servicePort: 8080
- path: /img
backend:
serviceName: img-service
servicePort: 8080
www.netkiller.cn --| Ingress |-> www.netkiller.cn www:80
| --------------> |
img.netkiller.cn --| |-> img.netkiller.cn img:80
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: vhost-ingress
spec:
rules:
- host: www.netkiller.cn
http:
paths:
- backend:
serviceName: www
servicePort: 80
- host: img.netkiller.cn
http:
paths:
- backend:
serviceName: img
servicePort: 80
http://www.netkiller.cn/1100 => /article/1100
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: rewrite-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /article/$1
spec:
rules:
- host: www.netkiller.cn
http:
paths:
# 可以有多個(可以正則)
- path: /($/.*)
backend:
serviceName: article
servicePort: 80
# 該註解只在配置了HTTPS之後才會生效進行跳轉 nginx.ingress.kubernetes.io/ssl-redirect: "true" # 強制跳轉到https,不論是否配置了https證書 nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
三種annotation按匹配優先順序順序:
canary-by-header > canary-by-cookie > canary-weight
# Release Version
apiVersion: v1
kind: Service
metadata:
name: hello-service
labels:
app: hello-service
spec:
ports:
- port: 80
protocol: TCP
selector:
app: hello-service
---
# canary Version
apiVersion: v1
kind: Service
metadata:
name: canary-hello-service
labels:
app: canary-hello-service
spec:
ports:
- port: 80
protocol: TCP
selector:
app: canary-hello-service
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: canary
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "30"
spec:
rules:
- host: canary.netkiller.cn
http:
paths:
- backend:
serviceName: canary-hello-service
$ for i in $(seq 1 10); do curl http://canary.netkiller.cn; echo '\n'; done
annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: "canary"
$ for i in $(seq 1 5); do curl -H 'canary:always' http://canary.netkiller.cn; echo '\n'; done
annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: "canary" nginx.ingress.kubernetes.io/canary-by-header-value: "true"
$ for i in $(seq 1 5); do curl -H 'canary:true' http://canary.netkiller.cn; echo '\n'; done