k8s入门教程四:通过2个实例来了解k8s

本文通过2个实例来了解k8s。第一个实例为TOMCAT+MYSQL实现在线打分系统,出处为Kubernetes权限指南(第四版);第二个实例为Kubernetes官方提供的PHP+Redis留言板的Hello World例子。

打分系统

此Java Web应用的结构比较简单,是一个运行在Tomcat里的Web App,如图1.1所示,JSP页面通过JDBC直接访问MySQL数据库并展示数据。出于演示和简化的目的,只要程序正确连接到了数据库,就会自动完成对应的Table的创建与初始化数据的准备工作。所以,当我们通过浏览器访问此应用时,就会显示一个表格的页面,数据则来自数据库。镜像下载链接为:https://hub.docker.com/r/kubeguide/tomcat-app

为MySQL服务创建一个RC定义文件mysql-rc.yaml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"

书上image写时没有加入mysql的版本号,由于现在最新版本是8.0,会出现异常,所以要修改为5.7。上述yaml表示创建一个RC资源,副本为1,启动mysql:5.7的镜像,mysql的root密码为123456。

再创建一个service,主要用来给集群内部的其他POD进行通信,表示新建一个名为mysql、端口为3306的svc,保存为mysql-svc.yaml:

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql

spec.selector确定了哪些Pod副本(实例)对应本服务。

下载kubeguide/tomcat-app:v1镜像,tomcat-rc.yaml

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

再创建一个svc,tomcat-svc.yaml

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
selector:
app: myweb

type=NodePort和nodePort=30001的两个属性表明此Service开启了NodePort方式的外网访问模式。在Kubernetes集群之外,比如在本机的浏览器里,可以通过30001这个端口访问myweb(对应到8080的虚端口上)。

开始创建:

1
2
3
4
kubectl create -f mysql-rc.yaml
kubectl create -f mysql-svc.yaml
kubectl create -f tomcat-rc.yaml
kubectl create -f tomcat-svc.yaml

再通过访问 http://192.168.1.60:30001/demo/ 即可成功访问了。

1
2
3
4
5
6
7
8
9
10
11
12
[root@master ~]# kubectl get svc mysql myweb
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mysql ClusterIP 10.103.193.69 <none> 3306/TCP 29d
myweb NodePort 10.99.245.12 <none> 8080:30001/TCP 29d
[root@master ~]# kubectl get rc mysql myweb
NAME DESIRED CURRENT READY AGE
mysql 1 1 1 29d
myweb 2 2 2 29d
[root@master ~]# kubectl get pods |egrep 'mysql|myweb'
mysql-qcznx 1/1 Running 37 29d
myweb-7p2db 1/1 Running 3 29d
myweb-lqr4n 1/1 Running 7 29d

可以看到正常运行了。那为什么tomcat就可以直接访问mysql呢?那我们进入myweb看一下代码:

1
2
3
4
5
6
[root@master ~]# kubectl exec -it myweb-lqr4n -- /bin/bash
root@myweb-lqr4n:/usr/local/tomcat# cd webapps/demo/
root@myweb-lqr4n:/usr/local/tomcat/webapps/demo# cat index.jsp |egrep 'getenv|getConnection'
String ip=System.getenv("MYSQL_SERVICE_HOST");
String port=System.getenv("MYSQL_SERVICE_PORT");
conn = java.sql.DriverManager.getConnection("jdbc:mysql://"+ip+":"+port+"?useUnicode=true&characterEncoding=UTF-8", "root","123456");

从代码上看,是通过获取环境变量的方式进行连接mysql的。如下:

1
2
3
4
5
6
7
root@myweb-lqr4n:/usr/local/tomcat/webapps/demo# env |grep MYSQL_SERVICE
MYSQL_SERVICE_PORT=3306
MYSQL_SERVICE_HOST=mysql
root@myweb-lqr4n:/usr/local/tomcat/webapps/demo# ping mysql
PING mysql.default.svc.cluster.local (10.103.193.69): 56 data bytes
^C--- mysql.default.svc.cluster.local ping statistics ---
16 packets transmitted, 0 packets received, 100% packet loss

MYSQL_SERVICE_HOST的值为mysql,直接 ping mysql 是可以解析的,解析出来的IP是 10.103.193.69,对应svc上面的IP。而mysql对应是svc的名字,在集群内部是可以解析的,解析时,会自动加上 default.svc.cluster.local

guestbook实例

这个实例是很经典的一个php+redis主备的实例。官方文档为:https://kubernetes.io/docs/tutorials/stateless-application/guestbook/

由于官方的镜像下载非常慢,就把需要使用到的镜像都推送到自己的仓库下面了。完整的yaml如下:

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
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: redis-master
labels:
app: redis
spec:
selector:
matchLabels:
app: redis
role: master
tier: backend
replicas: 1
template:
metadata:
labels:
app: redis
role: master
tier: backend
spec:
containers:
- name: master
image: fang2000/k8s-redis:e2e
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
app: redis
role: master
tier: backend
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis
role: master
tier: backend
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: redis-slave
labels:
app: redis
spec:
selector:
matchLabels:
app: redis
role: slave
tier: backend
replicas: 2
template:
metadata:
labels:
app: redis
role: slave
tier: backend
spec:
containers:
- name: slave
image: fang2000/k8s-gb-redisslave:v3
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-slave
labels:
app: redis
role: slave
tier: backend
spec:
ports:
- port: 6379
selector:
app: redis
role: slave
tier: backend
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: frontend
labels:
app: guestbook
spec:
selector:
matchLabels:
app: guestbook
tier: frontend
replicas: 3
template:
metadata:
labels:
app: guestbook
tier: frontend
spec:
containers:
- name: php-redis
image: fang2000/k8s-gb-frontend:v4
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
type: NodePort
ports:
- port: 80
selector:
app: guestbook
tier: frontend

将上述配置保存为文件,然后create之后,去查看各资源状态:

1
2
3
4
5
6
7
8
9
10
[root@master ~]# kubectl get svc frontend redis-master redis-slave
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend NodePort 10.99.157.67 <none> 80:31233/TCP 7d6h
redis-master ClusterIP 10.110.135.185 <none> 6379/TCP 7d6h
redis-slave ClusterIP 10.106.50.75 <none> 6379/TCP 7d6h
[root@master ~]# kubectl get deploy frontend redis-master redis-slave
NAME READY UP-TO-DATE AVAILABLE AGE
frontend 3/3 3 3 7d6h
redis-master 1/1 1 1 7d6h
redis-slave 2/2 2 2 7d6h

这时,可以打开 http://masterip:31233 来访问。

有时redis主备通信不正常,这时可以在pod上面安装一些软件。不过这是对于初学者而言的,原则上不能在pod里面安装任何软件的。

redis-slave使用的是debian7的系统,没有ps命令,需要安装procps

1
2
3
4
5
6
7
8
9
10
11
12
cat >/etc/apt/sources.list <<EOF
deb http://mirrors.163.com/debian/ stretch main non-free contrib
deb http://mirrors.163.com/debian/ stretch-updates main non-free contrib
deb http://mirrors.163.com/debian/ stretch-backports main non-free contrib
deb-src http://mirrors.163.com/debian/ stretch main non-free contrib
deb-src http://mirrors.163.com/debian/ stretch-updates main non-free contrib
deb-src http://mirrors.163.com/debian/ stretch-backports main non-free contrib
deb http://mirrors.163.com/debian-security/ stretch/updates main non-free contrib
deb-src http://mirrors.163.com/debian-security/ stretch/updates main non-free contrib
EOF
apt-get update
apt-get install procps telnet dnsutils iputils-ping

进入redis-slave,可以看到有个/run.sh的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root@redis-slave-6bf98b5d87-ghm7p:/data# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4180 580 ? Ss 13:26 0:00 /bin/sh -c /run.sh
root 6 0.0 0.0 17668 1472 ? S 13:26 0:00 /bin/bash /run.sh
root 7 0.6 0.0 36516 2316 ? Sl 13:26 0:49 redis-server *:6379
root 10 0.0 0.0 17880 2032 pts/0 Ss 13:59 0:00 /bin/bash
root 624 0.0 0.0 36624 1516 pts/0 R+ 15:26 0:00 ps aux
root@redis-slave-6bf98b5d87-ghm7p:/data# cat /run.sh
#!/bin/bash

...

if [[ ${GET_HOSTS_FROM:-dns} == "env" ]]; then
redis-server --slaveof ${REDIS_MASTER_SERVICE_HOST} 6379
else
redis-server --slaveof redis-master 6379
fi
root@redis-slave-6bf98b5d87-ghm7p:/data# echo $GET_HOSTS_FROM
env

root@redis-slave-6bf98b5d87-ghm7p:/data# redis-cli
127.0.0.1:6379> CONFIG GET slaveof
1) "slaveof"
2) "redis-master 6379"

怎么样去连接master是通过GET_HOSTS_FROM变量控制的。当 $GET_HOSTS_FROM 等于env时,运行 redis-server --slaveof ${REDIS_MASTER_SERVICE_HOST} 6379,而等于dns时,运行 redis-server --slaveof redis-master 6379。这时redis-master这个dns域名全称为 redis-master.default.svc.cluster.local,为svc的IP。

那如何测试是否正常呢?可以用ping以及telnet,但是ping是不通的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
root@redis-slave-7c7967fc54-4j8ln:/data# ping redis-master -c 1
PING redis-master.default.svc.cluster.local (10.110.135.185) 56(84) bytes of data.
^C
--- redis-master.default.svc.cluster.local ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

root@redis-slave-7c7967fc54-4j8ln:/data# telnet redis-master 6379
Trying 10.110.135.185...
Connected to redis-master.default.svc.cluster.local.
Escape character is '^]'.

root@redis-slave-7c7967fc54-4j8ln:/data# redis-cli
127.0.0.1:6379> keys *
1) "messages"
127.0.0.1:6379> get messages
",aaaa,bbbbbbbb"
127.0.0.1:6379>

wetty

未实现,待完善。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: kubectl-web
name: kubectl-web
spec:
replicas: 1
selector:
matchLabels:
run: kubectl-web
template:
metadata:
labels:
run: kubectl-web
spec:
containers:
- name: kubectl-web
image: swr.cn-south-1.myhuaweicloud.com/kevin-wangzefeng/cce-kubectl:v1
env:
- name: PASSWORD
value: "123456"

暴露出口:

kubectl expose deployment kubectl-web --type=NodePort --port=3000 --name=kubectl-web-svc

用户名:term

https://hub.docker.com/r/krishnasrinivas/wetty/

https://github.com/krishnasrinivas/wetty

  • 本文作者: wumingx
  • 本文链接: https://www.wumingx.com/k8s/kubernetes-guestbook.html
  • 本文主题: k8s入门教程四:通过2个实例来了解k8s
  • 版权声明: 本博客所有文章除特别声明外,转载请注明出处!如有侵权,请联系我删除。
0%