minikube addons enable ingress

由于大家都知道到原因,国内无法直接访问gcr.io和quay.io很多Kubernetes相关镜像无法从国内下载,网上很多大神也给出了薅aliyun羊毛的方案,我自己也试了几次也总是不能成功,使用aliyun提供minikube的版本也总是无法启动ingress。

通过查看启动ingress失败的POD信息发现是无法下载使用到镜像,于是按照网络指导按照如下步骤提前下载镜像到minikube节点,再启动ingress即可成功,具体操作如下:

  • 查询minikube版本对应的ingress镜像版本 使用kubectl get po -A查询ingress对应POD

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    kubectl get po -A
    NAMESPACE NAME READY STATUS RESTARTS AGE
    kube-system coredns-546565776c-xgggd 1/1 Running 0 27m
    kube-system etcd-minikube 1/1 Running 0 27m
    kube-system ingress-nginx-admission-create-d9dtl 0/1 Completed 0 28s
    kube-system ingress-nginx-admission-patch-x67q7 0/1 Completed 1 28s
    kube-system ingress-nginx-controller-7bb4c67d67-hp5c7 0/1 ContainerCreating 0 28s
    kube-system kube-apiserver-minikube 1/1 Running 0 27m
    kube-system kube-controller-manager-minikube 1/1 Running 0 27m
    kube-system kube-proxy-7wbct 1/1 Running 0 27m
    kube-system kube-scheduler-minikube 1/1 Running 0 27m
    kube-system storage-provisioner 1/1 Running 0 27m

    其中名字中包含ingress就是启动ingress新建到POD。

    再使用kubectl describe po ingress-nginx-xxx --namespace kube-system查询具体的失败信息,即可查询到失败原因为:获取镜像失败/超时。由于minikube 1.12.0版本以上的ingress镜像目前在阿里云上也无法下载,我们将minikube的版本切换到1.12.0版本,此时查询到的ingress插件依赖镜像信息如下:

    1
    2
    quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.32.0
    jettech/kube-webhook-certgen:v1.2.0

  • 手动安装ingress镜像 使用minikube ssh登录到minikube的节点上,再动过docker命令手工pull镜像。

    1
    2
    3
    docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:0.32.0
    docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:0.32.0 quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.32.0
    docker pull jettech/kube-webhook-certgen:v1.2.0

    quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.32.0 镜像可以由aliyun的镜像替代,再重新Tag成原有镜像。

  • 再次启用ingress 上述操作均成功以后可以再次启动ingress插件即可秒成功 :)

Kubernetes部署和升级应用

之前文章中我们都是用POD部署应用,特别是用POD部署应用时如果要更新应用程序,必须先更新镜像(Image)/配置(ConfigMap),删除POD再重新部署应用程序才能整整的更新。Kubernetes提供了更高级的应用部署和升级方法。

使用ReplicationController部署应用

   如果用ReplicationController(RC)部署的应用可以通过RC update来更新应用。 具体的kubia-rc.yaml文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: ReplicationController
metadata:
name: kubia
spec:
replicas: 3
selector:
app: kubia
template:
metadata:
name: kubia
labels:
app: kubia
spec:
containers:
- name: kubia
image: 172.17.0.1:5000/kubia:v1
ports:
- containerPort: 3000

使用kubectl create -f kubia-rc.yaml创建RC,部署成功以后即可看到根据RC的配置会产生3个副本kubectl get rc,po

1
2
3
4
5
6
7
8
9
kubectl get po,rc
NAME READY STATUS RESTARTS AGE
pod/kubia-bqszw 1/1 Running 0 62s
pod/kubia-c4cb9 1/1 Running 0 62s
pod/kubia-wxj55 1/1 Running 0 62s

NAME DESIRED CURRENT READY AGE
replicationcontroller/kubia 3 3 3 62s

当前POD到到镜像版本为v1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
kubectl describe po
Name: kubia-bqszw
Namespace: default
Priority: 0
Node: minikube/172.17.0.3
Start Time: Wed, 14 Oct 2020 20:29:56 +0800
Labels: app=kubia
Annotations: <none>
Status: Running
IP: 172.18.0.3
IPs:
IP: 172.18.0.3
Controlled By: ReplicationController/kubia
Containers:
kubia:
Container ID: docker://ec65afaeea2e8726530863981512165bec02ceb8e953a3d6575f6ea4ad7cc3f3
Image: 172.17.0.1:5000/kubia:v1
Image ID: docker-pullable://172.17.0.1:5000/kubia@sha256:0a9705988c08da5cc4fd535f40216a7b0ef89325b594ddb97ffcbd220c6731f1
...

通过kubectl set image rc/kubia kubia=172.17.0.1:5000/kubia:v2更新镜像。此时的应用程序并不会自动更新。当POD 异常或者手工删除以后RC 会自动拉起一个POD ,保证POD的副本数和RC 中配置的一致,此时新的POD 就是使用新的镜像创建应用,也就是说有的POD 使用新的镜像,有的POD 使用老的镜像。可以通过kubectl describe po查询到POD中容器的镜像版本不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
kubectl describe po
Name: kubia-c4cb9
Namespace: default
Priority: 0
Node: minikube/172.17.0.3
Start Time: Wed, 14 Oct 2020 20:29:56 +0800
Labels: app=kubia
Annotations: <none>
Status: Running
IP: 172.18.0.4
IPs:
IP: 172.18.0.4
Controlled By: ReplicationController/kubia
Containers:
kubia:
Container ID: docker://2b259af30a0c75987f027ac4516a7ea368774bbac4259a732f8141fdbcae376a
Image: 172.17.0.1:5000/kubia:v1
Image ID: docker-pullable://172.17.0.1:5000/kubia@sha256:0a9705988c08da5cc4fd535f40216a7b0ef89325b594ddb97ffcbd220c6731f1
Port: 3000/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 14 Oct 2020 20:30:04 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-d2hsm (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-d2hsm:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-d2hsm
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m43s default-scheduler Successfully assigned default/kubia-c4cb9 to minikube
Normal Pulled 6m36s kubelet Container image "172.17.0.1:5000/kubia:v1" already present on machine
Normal Created 6m36s kubelet Created container kubia
Normal Started 6m35s kubelet Started container kubia


Name: kubia-s6822 ‹--自动使用新的镜像创建新的POD
Namespace: default
Priority: 0
Node: minikube/172.17.0.3
Start Time: Wed, 14 Oct 2020 20:35:57 +0800
Labels: app=kubia
Annotations: <none>
Status: Running
IP: 172.18.0.6
IPs:
IP: 172.18.0.6
Controlled By: ReplicationController/kubia
Containers:
kubia:
Container ID: docker://91fd664961c798256afbfd9b2e6cd47697a817f27803812da26e28d56212371e
Image: 172.17.0.1:5000/kubia:v2
Image ID: docker-pullable://172.17.0.1:5000/kubia@sha256:0709bbd6e3a34f306a16207b79b045e6a4bf33c22a3e7a88404166caee41e51f
Port: 3000/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 14 Oct 2020 20:36:02 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-d2hsm (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-d2hsm:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-d2hsm
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 42s default-scheduler Successfully assigned default/kubia-s6822 to minikube
Normal Pulled 38s kubelet Container image "172.17.0.1:5000/kubia:v2" already present on machine
Normal Created 37s kubelet Created container kubia
Normal Started 37s kubelet Started container kubia


Name: kubia-wxj55
Namespace: default
Priority: 0
Node: minikube/172.17.0.3
Start Time: Wed, 14 Oct 2020 20:29:56 +0800
Labels: app=kubia
Annotations: <none>
Status: Running
IP: 172.18.0.2
IPs:
IP: 172.18.0.2
Controlled By: ReplicationController/kubia
Containers:
kubia:
Container ID: docker://a5195a7ec8573d429445f7c79218372abc887d360b3564c8659b600c236c0248
Image: 172.17.0.1:5000/kubia:v1
Image ID: docker-pullable://172.17.0.1:5000/kubia@sha256:0a9705988c08da5cc4fd535f40216a7b0ef89325b594ddb97ffcbd220c6731f1
Port: 3000/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 14 Oct 2020 20:30:04 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-d2hsm (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-d2hsm:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-d2hsm
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m44s default-scheduler Successfully assigned default/kubia-wxj55 to minikube
Normal Pulled 6m36s kubelet Container image "172.17.0.1:5000/kubia:v1" already present on machine
Normal Created 6m36s kubelet Created container kubia
Normal Started 6m35s kubelet Started container kubia

使用ReplicationController部署应用,需要手工选择POD 逐一进行升级。实际部署应用过程中我们希望这个过程可以可控、且自动完成,这就需要通过更高级更高级的概念来部署应用。

使用Deployment部署应用

   Kubernetes提供更高级的概念来实现应用的部署、滚动升级以及回滚。一个典型的kubernetes的应用会包含:POD、RepliciaSet以及Deployment。他们之间的关系如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: apps/v1
kind: Deployment
metadata:
name: kubia
spec:
replicas: 3
selector:
matchLabels:
app: kubia
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: 172.17.0.1:5000/kubia:v1

还是上面的例子,这次将ReplicationController的yaml文件中kinde替换城Deployment,并另存为kubia-deploymnent.yaml,使用kubectl create -f kubia-deployment.yaml重新部署应用,部署成功以后可以功过kubectl get po,rs,deployment查询部署的应用情况。

1
2
3
4
5
6
7
8
9
10
11
12
kubectl get po,rs,deployment
NAME READY STATUS RESTARTS AGE
pod/kubia-7fc889c9c9-b7b8f 1/1 Running 1 21h
pod/kubia-7fc889c9c9-lp7m8 1/1 Running 1 21h
pod/kubia-7fc889c9c9-qkz9w 1/1 Running 1 21h

NAME DESIRED CURRENT READY AGE
replicaset.apps/kubia-7fc889c9c9 3 3 3 21h

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/kubia 3/3 3 3 21h

通过kubectl descibe po查询到POD到详细情况如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
kubectl describe po
Name: kubia-7fc889c9c9-b7b8f
Namespace: default
Priority: 0
Node: minikube/172.17.0.3
Start Time: Tue, 13 Oct 2020 22:44:19 +0800
Labels: app=kubia
pod-template-hash=7fc889c9c9
Annotations: <none>
Status: Running
IP: 172.18.0.2
IPs:
IP: 172.18.0.2
Controlled By: ReplicaSet/kubia-7fc889c9c9
Containers:
kubia:
Container ID: docker://aa524c986c27e53d12961173a5a0adf43a3554e13aeac5fc1c5cca083da09271
Image: 172.17.0.1:5000/kubia:v1 ‹-- 镜像版本是v1
Image ID: docker-pullable://172.17.0.1:5000/kubia@sha256:0a9705988c08da5cc4fd535f40216a7b0ef89325b594ddb97ffcbd220c6731f1
...

更新应用

  • 配置更新镜像

kubectl set image deployment/kubia kubia=172.17.0.1:5000/kubia:v2

设置完成以后deployment会自动滚动升级,可以通过kubectl rollout deployment/kubia status查询升级状态,此时查询应用部署的详情可以看到PO,RS更新中或者已经更新成功。 kubectl get po,rs,deployment 其中存在2个rs,一个升级前的rs,一个是当前到rs。

1
2
3
4
5
6
7
8
9
10
11
12
13
kubectl get po,rs,deployment
NAME READY STATUS RESTARTS AGE
pod/kubia-7fc889c9c9-b7b8f 1/1 Running 1 21h
pod/kubia-7fc889c9c9-lp7m8 1/1 Running 1 21h
pod/kubia-7fc889c9c9-qkz9w 1/1 Running 1 21h
pod/kubia-84ddcd9474-bv8fl 0/1 ContainerCreating 0 3s ‹-- 新建POD

NAME DESIRED CURRENT READY AGE
replicaset.apps/kubia-7fc889c9c9 3 3 3 21h ‹-- 升级前的rs
replicaset.apps/kubia-84ddcd9474 1 1 0 4s ‹-- 当前的rs

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/kubia 3/3 1 3 21h

查询POD详细信息,可以看到新建到POD已经更新为新到镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
kubectl describe po kubia-84ddcd9474-bv8fl                                  ‹-- 新建POD
Name: kubia-84ddcd9474-bv8fl
Namespace: default
Priority: 0
Node: minikube/172.17.0.3
Start Time: Wed, 14 Oct 2020 20:19:12 +0800
Labels: app=kubia
pod-template-hash=84ddcd9474
Annotations: <none>
Status: Running
IP: 172.18.0.6
IPs:
IP: 172.18.0.6
Controlled By: ReplicaSet/kubia-84ddcd9474
Containers:
kubia:
Container ID: docker://3de190659e28bebcde082b287c7c4c434ab706c08654f6d1c7db3db455304508
Image: 172.17.0.1:5000/kubia:v2 ‹-- 镜像版本是v2
Image ID: docker-pullable://172.17.0.1:5000/kubia@sha256:0709bbd6e3a34f306a16207b79b045e6a4bf33c22a3e7a88404166caee41e51f

  • 管理升级

此时如果使用kubectl rollout undo deployment/kubia 即可全部回滚应用,可以通过kubectl rollout pause/resume/restart/history等控制滚动升级过程(如果测试过程中难以观察到升级过程,可以讲deployment中副本数量调高)。


此外,也可以使用StatefulSet部署有状态应用。StatefulSet和Deployment最大的区别是为每个副本POD实例提供店里存储,可以保证POD副本有固定的名字和主机,可以按照预期的顺序启停POD副本。

Kubernetes使用ConfigMap配置应用程序(二)

上一篇学习了通过args方式还是env方式都是将配置应用,配置参数硬编码在POD配置文件中,实际应用部署的过程中,我们希望配置参数和POD配置能够解藕,今天我们就看一下如何用ConfigMap配置应用。

创建一个ConfigMap

  • 使用命令行创建
1
kubectl create configmap fortune-configmap --from-literal=sleep-interval=60

创建成功以后可以通过kubectl命令查询configmap的配置。

kubectl get configmap fortune-configmap -o yaml 查询结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
data:
sleep-interval: "60"
kind: ConfigMap
metadata:
creationTimestamp: "2020-09-29T12:29:40Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:sleep-interval: {}
manager: kubectl-create
operation: Update
time: "2020-09-29T12:29:40Z"
name: fortune-configmap
namespace: default
resourceVersion: "2434"
selfLink: /api/v1/namespaces/default/configmaps/fortune-configmap
uid: a6562e65-1431-47b1-b153-e4c270561a2c
  • 使用yaml文件创建

上述查询到信息将metadata中只保留名称就可以创建一个简单的ConfigMap配置文件,使用如下命令即可通过文件创建ConfigMap kubectl create -f fortune-congfigmap.yaml

在POD文件中使用CongfigMap配置应用

  • 使用环境变量配置应用 修改POD配置文件,使用ConfigMap配置env参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
apiVersion: v1
kind: Pod
metadata:
name: fortune-env
labels:
app: fortune-env
spec:
containers:
- name: html-gen
image: 172.17.0.1:5000/fortune:env
env:
- name: INTERVAL
valueFrom:
configMapKeyRef:
name: fortune-configmap
key: sleep-interval
volumeMounts:
- name: html
mountPath: /var/htdocs
- name: log
mountPath: /var/log/fortune
- name: web-server
image: 172.17.0.1:500/nginx:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
- name: log-server
image: 172.17.0.1:5000/nginx:log
volumeMounts:
- name: log
mountPath: /usr/share/nginx/log
readOnly: true
ports:
- containerPort: 8080
protocol: TCP
volumes:
- name: html
emptyDir: {}
- name: log
emptyDir: {}

重新创建PODkubectl create -f fortune-pod-env.yaml, 此时再查询fortune每个60秒更新一次。实际应用部署时,也可以修改ConfigMap的配置,当新新建POD时会使用新的ConfigMap值。

  • 使用参数配置应用

和使用环境变量配置POD类似,修改POD配置文件,使用ConfigMap配置args参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
apiVersion: v1
kind: Pod
metadata:
name: fortune-args
labels:
app: fortune-args
spec:
containers:
- name: html-gen
image: 172.17.0.1:5000/fortune:args
env:
- name: INTERVAL
valueFrom:
configMapKeyRef:
name: fortune-configmap
key: sleep-interval
args: [$(INTERVAL)]
volumeMounts:
- name: html
mountPath: /var/htdocs
- name: log
mountPath: /var/log/fortune
- name: web-server
image: 172.17.0.1:500/nginx:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
- name: log-server
image: 172.17.0.1:5000/nginx:log
volumeMounts:
- name: log
mountPath: /usr/share/nginx/log
readOnly: true
ports:
- containerPort: 8080
protocol: TCP
volumes:
- name: html
emptyDir: {}
- name: log
emptyDir: {}

创建PODkubectl create -f fortune-pod-args.yaml, 此时查询fortune每个60秒更新一次。

此时,如果删除旧的ConfigMap,重新配置一个新的ConfigMap,再同时删除frotune-env pod和fortune-args pod并重新新建POD时会使用新的ConfigMap值。

ConfigMap可以配置的资源

从文件、文件夹和字符创建的ConfigMap

Kubernetes使用ConfigMap配置应用程序(一)

传统的应用程序在部署时往往需要通过命令行参数、环境变量、配置文件等方式配置应用程序。Kubernetes应用程序可以通过ConfigMap和Secret来配置应用程序。ConfigMap和Secret的区别主要是Secret用于敏感数据配置,数据在Kubernetes中是加密存储的。

选择ConfigMap和Secret的原则比较简单:

  • 非敏感数据则使用ConfigMap配置;
  • 敏感数据使用Secret配置;
  • 如果既有敏感数据又有非敏感数据则使用Secret配置。

ConfigMap和Secret使用方式类似,这里主要描述ConfigMap的使用方式。

这次还是以fortune应用程序为例,通过ConfigMap向fortune传递参数调整程序刷新的时间间隔。首先我看一下不借助ConfigMap我们如何通过命令参数和环境变量配置应用。

1.使用命令参数配置应用

修改fortune镜像,增加间隔参数

  • 修改fortuneloop.sh,增加间隔参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#! /bin/bash
trap "exit" SIGINT
INTERVAL=$1

mkdir /var/htdocs
mkdir /var/fortune

echo Configured to generate new fortune every $INTERVAL seconds.

while :
do
echo $(date) writing fortune to /var/htdocs/index.html >> /var/log/fortune/$(date +%Y-%m-%d).log
/usr/games/fortune > /var/htdocs/index.html

sleep $INTERVAL
done
  • 修改Dockerfile增加默认参数
1
2
3
4
5
6
FROM ubuntu:latest
RUN apt update ; apt install -y fortune
ADD fortuneloop.sh /bin/fortuneloop.sh

ENTRYPOINT ["/bin/fortuneloop.sh"]
CMD ["10"]

重新制作镜像:docker build -t 172.17.0.1:5000/fortune:args .,并推送本地镜像仓库

  • 本地运行镜像测试
1
2
docker run --name fortune-args -it 172.17.0.1:5000/fortune:args 15
Configured to generate new fortune every 15 seconds.

在POD中使用args覆盖容器参数

  • 修改POD配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
apiVersion: v1
kind: Pod
metadata:
name: fortune
labels:
app: fortune
spec:
containers:
- name: html-gen
image: 172.17.0.1:5000/fortune:args
args: ["30"]
volumeMounts:
- name: html
mountPath: /var/htdocs
- name: log
mountPath: /var/log/fortune
- name: web-server
image: 172.17.0.1:500/nginx:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
- name: log-server
image: 172.17.0.1:5000/nginx:log
volumeMounts:
- name: log
mountPath: /usr/share/nginx/log
readOnly: true
ports:
- containerPort: 8080
protocol: TCP
volumes:
- name: html
emptyDir: {}
- name: log
emptyDir: {}

这样重新创建POD即可看到应用参数更新成"30"秒。

2.使用环境变量配置应用

修改fortune镜像,增加间隔环境变量

  • 修改fortuneloop.sh,使用INTERVAL代替默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#! /bin/bash
trap "exit" SIGINT
mkdir /var/htdocs
mkdir /var/fortune

echo Configured to generate new fortune every $INTERVAL seconds.

while :
do
echo $(date) writing fortune to /var/htdocs/index.html >> /var/log/fortune/$(date +%Y-%m-%d).log
/usr/games/fortune > /var/htdocs/index.html

sleep $INTERVAL
done
  • 修改Dockerfile增加默认参数
1
2
3
4
5
FROM ubuntu:latest
RUN apt update ; apt install -y fortune
ADD fortuneloop.sh /bin/fortuneloop.sh

ENTRYPOINT ["/bin/fortuneloop.sh"]

重新制作镜像:docker build -t 172.17.0.1:5000/fortune:env .,并推送本地镜像仓库

在POD中使用env覆盖容器参数

  • 修改POD配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
apiVersion: v1
kind: Pod
metadata:
name: fortune
labels:
app: fortune
spec:
containers:
- name: html-gen
image: 172.17.0.1:5000/fortune:env
env:
- name: INTERVAL
value: "45"
volumeMounts:
- name: html
mountPath: /var/htdocs
- name: log
mountPath: /var/log/fortune
- name: web-server
image: 172.17.0.1:500/nginx:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
- name: log-server
image: 172.17.0.1:5000/nginx:log
volumeMounts:
- name: log
mountPath: /usr/share/nginx/log
readOnly: true
ports:
- containerPort: 8080
protocol: TCP
volumes:
- name: html
emptyDir: {}
- name: log
emptyDir: {}

这样重新创建POD即可看到应用参数更新成"45"秒。

上述两种方式,无论时通过args方式还是env方式都是将配置参数硬编码在POD配置文件中。实际应用部署的过程中,我们希望配置参数和POD配置能够解藕,这个就需要用到Kubernetes提供的ConfigMap来实现。

Kubernetes挂载存储

示例说明

为演示在Kubernetes挂载存储以下面为例:

  • fortune进程 利用fortune游戏每10秒钟更新一次html文档;并将更新过程钟写入日志。

  • web-server进程 使用nginx作为web服务器向外提供服务,客户展示fortune生成的html文件。

  • log-server进程 使用nginx作为服务器向外提供服务,可以查询fortune日志。

分别将上述进程部署到不同的容器中,容器间通过挂载emptyDir卷共享信息。

测试代码

  • fortune程序
1
2
3
4
5
6
7
8
9
10
11
12
#! /bin/bash
trap "exit" SIGINT
mkdir /var/htdocs
mkdir /var/fortune

while :
do
echo $(date) writing fortune to /var/htdocs/index.html >> /var/log/fortune/$(date +%Y-%m-%d).log
/usr/games/fortune > /var/htdocs/index.html

sleep 10
done

每10秒钟生成一次html文件,并记录生成日志

  • fortune的dockerfile
1
2
3
4
5
FROM ubuntu:latest
RUN apt update ; apt install -y fortune
ADD fortuneloop.sh /bin/fortuneloop.sh

ENTRYPOINT /bin/fortuneloop.sh
  • 将三个示例容器部署到一个POD中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: v1
kind: Pod
metadata:
name: fortune
labels:
app: fortune
spec:
containers:
- name: html-gen
image: 172.17.0.1:5000/fortune
volumeMounts:
- name: html
mountPath: /var/htdocs
- name: log
mountPath: /var/log/fortune
- name: web-server
image: 172.17.0.1:500/nginx:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
- name: log-server
image: 172.17.0.1:5000/nginx:log
volumeMounts:
- name: log
mountPath: /usr/share/nginx/log
readOnly: true
ports:
- containerPort: 8080
protocol: TCP
volumes:
- name: html
emptyDir: {}
- name: log
emptyDir: {}

nginx:log源于nginx:alpine镜像,只是将nginx默认80端口修改成8080端口,将默认的html root目录修改成/usr/share/nginx/log目录,具体修改方法下次在详细讲。

  • 建立一个NodePort类型的Service对外提供web服务
1
2
3
4
5
6
7
8
9
10
11
12
13
kind: Service
apiVersion: v1
metadata:
name: fortune-web-nodeport
spec:
selector:
app: fortune
type: NodePort
ports:
- port: 8088
targetPort: 80
nodePort: 30157

注意selector实际是按照POD中容器标签进行选择的,因此该信息必须和POD中设置的标签保持一致; targetPort和容器端口一致,nginx:alpine默认端口是80端口

  • 建立一个NodePort类型的Service对外提供log服务
1
2
3
4
5
6
7
8
9
10
11
12
kind: Service
apiVersion: v1
metadata:
name: fortune-log-nodeport
spec:
selector:
app: fortune
type: NodePort
ports:
- port: 8090
targetPort: 8080
nodePort: 30159

注意selector实际是按照POD中容器标签进行选择的,因此该信息必须和POD中设置的标签保持一致; targetPort和容器端口一致,nginx:log默认端口是8080端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: fortune-ingress
spec:
rules:
- host: fortune-web.local.com
http:
paths:
- path: /
backend:
serviceName: fortune-web-nodeport
servicePort: 8088
- host: fortune-log.local.com
http:
paths:
- path: /
backend:
serviceName: fortune-log-nodeport
servicePort: 8090

通过Ingress对外提供访问策略,分别根据不同的域名选择到不同的服务中。 新版本的Kubernetes提供了新的网络策略接口,在后续文章中详细测试。

  • 配置域名和IP地址

在minikube中创建ingress后可以通过:kubectl get ingress 查询ingress信息,该信息中包含了域名和IP地址的对应信息,在/etc/hosts中配置该信息即可在本机通过域名访问服务。

测试结果

  • 查询资源信息

  • 修改hosts文件

  • 访问web和log服务

Kubernetes将服务暴露给外部方式

kubernets集群内部的服务可以直接环境变量、内部DNS等方式被发现,并在集群内部提供服务。如何将Kubernetes的服务暴露给外部客户端呢? Kubernetes提供以下集中方式将服务暴露给开外部客户端:

通过NodePort暴露服务

顾名思义,将服务类型设置成NodePort方式,Kubernetes会在集群每个节点上打开一个端口,将该端口的流量转发到服务的POD。

通过负载均衡器暴露

负载均衡方式实际是NodePort方式的增强,将服务类型设置成LoadBalancer方式实际是通过云基础架构提供的负载均衡器,将流量转发到集群内部的NodePort上。

通过Ingress暴露

Ingress是Kubernetes一种资源,通过类似LoadBalancer类似的能力,区别在于每个LoadBalancer都需要一个独立的公网IP,而Ingress只需要一个公网IP即可根据规则将流量转发到对应的服务。

Kubernetes发现服务

Kubernetes发现服务

由于Kubernetes的POD的生命是短暂的,可以随时被创建和销毁,不能通过指定IP和端口号被客户端发现。另外,对于水平伸缩的POD,由多个POD提供服务,客户端也无需关心由那个POD提供服务,也就无需关心POD的部署位置。

通过引入服务(Service)提供稳定外部访问机制。

我们可以为服务创建多个端口。例如:一个servcie可以有80和443端口,通过80和443端口将外部访问转发到POD的8080和8443端口。

  • 服务发现
    • 通过环境变量发现服务 服务的创建早于POD,POD创建时k8s会通过环境变量发现服务;

    • 通过DNS发现服务 k8s集群提供了一个kube-dns POD,所有的POD都使用DNS(通过修改POD的/etc/resolv.conf文件实现)。

    • 通过FQPN发现服务

使用minikube部署本地镜像

启用本地镜像Hub

  • 使用如下命令启动本地镜像仓库

    sudo docker run -d -p 5000:5000 --restart=always --name registry registry

  • 查询是否启用成功

    curl -X GET 172.17.0.1:5000/v2/_catalog

    因为当前没有Push任何镜像到本地镜像仓库,查询结果是空。

Push镜像到local Hub

  • 为本地镜像打一个tag

    docker tag kubia 172.17.0.1:5000/kubia

  • 向本地镜像仓库推送镜像

    docker push 172.17.0.1:5000/kubia

  • 再次查询本地镜像仓库

    curl -X GET 172.17.0.1:5000/v2/_catalog

    返回: {"repositories":["kubia"]}

添加本地镜像到配置文件

sudo vim /etc/docker/daemon.json

加入如下信息:

1
2
3
4
5
6
7
8
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://registry.docker-cn.com"
],
"insecure-registries":["172.17.0.1:5000"] //增加本地镜像地址
}

这里的配置需要注意:172.17.0.1:5000,需要和tag镜像信息保持一致; 重启docker服务是配置生效: systemctl restart docker

新建一个minikube集群

minikube start --driver=docker --insecure-registry="172.17.0.1:5000" --registry-mirror="https://hub-mirror.c.163.com"

这里的本地ip地址必须和上述配置的一致。 由于docker pull镜像默认使用的https协议,因此需要明确告诉docker服务和minikube使用http协议(insecure-registry)

从local registry运行一个docker应用

  • 运行docker应用

    kubectl run kubia --image=172.17.0.1:5000/kubia --port 3000

    系统会返回:pod/kubia created

    docker run是运行一个rs,而不是delploy一个应用,无需要指定部署文件

  • 查询POD信息

    kubectl get pods,系统会返回pod运行状态,如果有异常可以使用 kubectl describe pod kubia 查询详细信息。

    1
    2
    NAME    READY   STATUS    RESTARTS   AGE
    kubia 1/1 Running 0 16s

  • 创建服务对象 此时虽然已经集群内部部署成功,应用仍然无法从集群外部访问,此时需要通过服务开放接口

    sudo kubectl expose pod kubia --name kubia-http --type=LoadBalancer

    由于minikube不支持LoaderBalancer类型,使用默认的type类型也可以。

  • 列出服务

    kubectl get services 系统返回服务信息:

    1
    2
    3
    NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
    Kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13m
    kubia-http LoadBalancer 10.99.35.111 <pending> 3000:31902/TCP 97s
    此时查询到服务仍然未分配外部IP,minikube可以使用 minikube service kubia-http访问的服务的IP和端口。

    1
    2
    3
    4
    5
    6
    |-----------|------------|-------------|---------------------------|
    | NAMESPACE | NAME | TARGET PORT | URL |
    |-----------|------------|-------------|---------------------------|
    | default | kubia-http | 3000 | http://192.168.3.15:31902 |
    |-----------|------------|-------------|---------------------------|

    使用http://192.168.3.15:31902即可访问服务。

pod,service和rc之间的关系

镜像推送部署和应用部署流程

在Windwos 10 WSL2中安装Docker

最近在学习kubernets,正在阅读《Kubernetes in action》一书,为了感性化的理解书中内容决定同步在办公PC上安装书中涉及到工具和代码,今天先完成在win 10 WSL2中安装Docker。首先在win 10 WSL2中安装Docker想法是基于微软宣称的WSL2内核是真正的Linux内核,也就想当然的认为WSL2中的Ubuntu 20.04和在PC上直接安装是一致的,结果在安装过程中遇到各种小插曲。

打开硬件虚拟化支持

在BIOS中设置Intel虚拟化支持,进入到Virtualization选项中,设置Intel Virtual Technology为enable。重启以后即可在windows任务管理器-〉性能面板中查询虚拟化已开启。

升级WSL-〉WSL2

  • 升级win10到支持WLS2版本,Version 2004, Build 19041 or higher;

  • 设置WSL版本 在cmd中输入如下命令:wsl --set-default-version 2,将wsl版本设置为WSL2。

  • 安全ubuntu 20.04 在windows store中搜索ubuntu 20.04,安装ubuntu 20.04版本;安装完成后启动ubuntu 20.04系统提示

详细配置参考:https://docs.microsoft.com/en-us/windows/wsl/

安装Docker

  • 安装windows 10版本的Docker 不要直接使用系统apt的命令安装docker.io;建议下载windows 10的Docker版本,设置启动WSL即可。
  • 检查Docker安装是否成功 使用:sudo docker version查询docker版本: ### 如果显示如下信息则说明server端没有启动或者连接失败:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Client:
    Version: 19.03.12-ce
    API version: 1.40
    Go version: go1.14.4
    Git commit: 48a66213fe
    Built: Wed Jul 1 17:05:50 2020
    OS/Arch: linux/amd64
    Experimental: false
    Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.40/version": dial unix /var/run/docker.sock: connect: permission denied

  • 解决方案:
    • 使用sudo docker version查询,如果仍然显示失败;
    • 检查server是否启动

如果显示如下信息则说明启动成功:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Client:
Version: 19.03.12-ce
API version: 1.40
Go version: go1.14.4
Git commit: 48a66213fe
Built: Wed Jul 1 17:05:50 2020
OS/Arch: linux/amd64
Experimental: false

Server:
Engine:
Version: 19.03.12-ce
API version: 1.40 (minimum version 1.12)
Go version: go1.14.4
Git commit: 48a66213fe
Built: Wed Jul 1 17:05:26 2020
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.3.4.m
GitCommit: d76c121f76a5fc8a462dc64594aea72fe18e1178.m
runc:
Version: 1.0.0-rc91
GitCommit: 24a3cf88a7ae5f4995f6750654c0e2ca61ef4bb2
docker-init:
Version: 0.18.0
GitCommit: fec3683

## 配置Docker

配置国内源

在Windows中配置国内源 配置Dokcer国内源时需要打开(图形化的)Docker Desktop,直接设置国内源即可;如果 在Linux系统中配置源,直接修改/etc/docker/daemon.json文件即可。详细请参考:https://docs.docker.com/registry/recipes/mirror/ 配置文件格式为JSON格式,例如:

1
2
3
{
"registry-mirrors": ["https://<my-docker-mirror-host>"]
}

常用的国内Docker如下: - docker官方中国区: https://registry.docker-cn.com - 网易: http://hub-mirror.c.163.com - ustc: http://docker.mirrors.ustc.edu.cn 可以同时配置多个源,例如:

1
2
3
4
5
6
{
"registry-mirrors": [
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com"
]
}

重启Docker服务即可生效

在Linux执行如下命令:

1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

如果重启提示错误可以可根据提示的命令定位错误原因。 > Job for docker.service failed because the control process exited with error code. > > See "systemctl status docker.service" and "journalctl -xe" for details.

查询配置是否生效

sudo docker info