本文是通过 yum 方式安装 Kubernetes, 并部署 tomcat+MySQL 实现 Jave web 应用. 此应用是 JSP 页面通过 JDBC 访问 MySQL 数据库, 只要程序正确连接到数据库上, 就会自动完成对应的 Table 的创建与初始化数据的准备工作. 当我们通过浏览器访问此应用时, 就会显示一个表格的页面, 数据则来自数据库.
此应用需要启动两个容器: Web App 容器和 MySQL 容器, 并且 Web App 容器需要访问 MySQL 容器. 现在我们就来看看通过 Kubernetes 是如何实现 Java Web 应用的.
在继续阅读之前, 我们需要对 Kubernetes 有一个基本的认识, 需要了解它的原理, 核心架构, 核心组件和对象, 以及各组件之间的联系等基础概念, 可以参考我的上一篇博文《初识 Kubernetes(K8s): 理论基础》,http://blog.51cto.com/andyxu/2308937
系统环境
操作系统: CentOS 7.5 64 位
IP 地址: 192.168.2.238
一, 安装部署 Kubernetes(K8s)
1, 关闭 CentOS 自带的防火墙服务
注: Kubernetes 集群之间会有大量的网络通信, 在一个安全的内部网络环境中建议关闭防火墙服务
- [root@andyxu-test ~]# systemctl disable firewalld
- [root@andyxu-test ~]# systemctl stop firewalld
2, 安装 etcd 和 Kubernetes 软件(会自动安装 Docker 软件)
[root@andyxu-test ~]# yum -y install etcd kubernetes
注: yum 方式安装的 kubernetes 的版本是 1.5.2
3, 生成 rhsm 证书文件
- [root@andyxu-test ~]# wget http://mirror.centos.org/centos/7/os/x86_64/Packages/python-rhsm-certificates-1.19.10-1.el7_4.x86_64.rpm
- [root@andyxu-test ~]# rpm2cpio python-rhsm-certificates-1.19.10-1.el7_4.x86_64.rpm | cpio -iv --to-stdout ./etc/rhsm/ca/RedHat-uep.pem | tee /etc/rhsm/ca/RedHat-uep.pem
注: 创建容器时需要从 RedHat 站点下载 pod-infrastructure:latest 镜像, 如果没有此证书文件会报错, Pod 会一直显示 ContainerCreating 状态.
4, 修改 docker 和 kube-apiserver 的配置文件
docker 配置文件为 / etc/sysconfig/docker, 将 OPTIONS 的内容修改为
OPTIONS='--selinux-enabled=false --insecure-registry gcr.io'
kube-apiserver 配置文件为 / etc/kubernetes/apiserver, 修改 KUBE_ADMISSION_CONTROL 的内容, 将 --admission-control 参数中的 ServiceAccount 删除.
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota"
5, 按顺序启动所有服务
- [root@andyxu-test ~]# systemctl start etcd
- [root@andyxu-test ~]# systemctl start docker
- [root@andyxu-test ~]# systemctl start kube-apiserver
- [root@andyxu-test ~]# systemctl start kube-controller-manager
- [root@andyxu-test ~]# systemctl start kube-scheduler
- [root@andyxu-test ~]# systemctl start kubelet
- [root@andyxu-test ~]# systemctl start kube-proxy
二, 创建并配置 MySQL 容器
1, 创建 MySQL 的 Deployment 定义文件
MySQL-dep.YAML 文件内容如下:
- apiVersion: extensions/v1beta1 #apiserver 的版本
- kind: Deployment #副本控制器 deployment, 管理 pod 和 RS
- metadata:
- name: MySQL #deployment 的名称, 全局唯一
- spec:
- replicas: 1 #Pod 副本期待数量
- selector:
- matchLabels: #定义 RS 的标签
- App: MySQL #符合目标的 Pod 拥有此标签
- strategy: #定义升级的策略
- type: RollingUpdate #滚动升级, 逐步替换的策略
- template: #根据此模板创建 Pod 的副本(实例)
- metadata:
- labels:
- App: MySQL #Pod 副本的标签, 对应 RS 的 Selector
- spec:
- containers: #Pod 里容器的定义部分
- - name: MySQL #容器的名称
- image: MySQL:5.7 #容器对应的 docker 镜像
- volumeMounts: #容器内挂载点的定义部分
- - name: time-zone #容器内挂载点名称
- mountPath: /etc/localtime #容器内挂载点路径, 可以是文件或目录
- - name: MySQL-data
- mountPath: /var/lib/MySQL #容器内 MySQL 的数据目录
- - name: MySQL-logs
- mountPath: /var/log/MySQL #容器内 MySQL 的日志目录
- ports:
- - containerPort: 3306 #容器暴露的端口号
- env: #写入到容器内的环境容量
- - name: MYSQL_ROOT_PASSWORD #定义了一个 MySQL 的 root 密码的变量
- value: "123456"
- volumes: #本地需要挂载到容器里的数据卷定义部分
- - name: time-zone #数据卷名称, 需要与容器内挂载点名称一致
- hostPath:
- path: /etc/localtime #挂载到容器里的路径, 将 localtime 文件挂载到容器里, 可让容器使用本地的时区
- - name: MySQL-data
- hostPath:
- path: /data/MySQL/data #本地存放 MySQL 数据的目录
- - name: MySQL-logs
- hostPath:
- path: /data/MySQL/logs #本地存入 MySQL 日志的目录
apiVersion: 定义使用 apiserver 的哪个版本, 可通过 kubectl API-versions 命令查看 apiserver 有哪些版本;
kind: 用来表明此资源对象的类型, 比如这里的值为 "Deployment", 表示这是一个 deployment;
spec:RS 相关属性定义, spec.selector 是 RS 的 Pod 标签 (Label) 选择器, 即监控和管理拥有这些标签的 Pod 实例, 确保当前集群上始终有且仅有 replicas 个 Pod 实例在运行, 这里设置 replicas=1 表示只能运行一个 MySQL Pod 实例.
spec.strategy: 定义 Pod 的升级方案, Recreate 表示删除所有已存在的 Pod, 重新创建新的; RollingUpdate 表示滚动升级, 逐步替换的策略, 滚动升级时支持更多的附加参数, 例如设置最大不可用 Pod 数量, 最小升级间隔时间等等.
spec.template: 当集群中运行的 Pod 数量小于 replicas 时, RS 会根据 spec.template 中定义的 Pod 模板来生成一个新的 Pod 实例, spec.template.metadata.labels 指定了该 Pod 的标签, 需要特别注意的是, 这里的 labels 必须匹配之前的 spec.selector.
spec.template.spec.containers: 容器的定义部分, 包括容器的名称, 使用的 docker 镜像, 挂载数据卷, 服务的端口号, 变量等内容.
spec.template.spec.volumes: 需要挂载到容器里的本地数据卷的定义部分, 数据卷的名称要与容器内挂载点的名称一致, path 定义本地的数据卷路径.
2, 创建 deployment,RS,Pod 和容器
创建过程需要先下载镜像, 时间会比较久, 可喝杯茶撩撩旁边的妹子, 哈哈, 请耐心等待
- [root@andyxu-test ~]# kubectl create -f MySQL-dep.YAML
- deployment "mysql" created
3, 查看创建好的 deployment 运行情况
- [root@andyxu-test ~]# kubectl get deployment
- NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
- MySQL 1 1 1 1 8s
注: 都是 1 表示运行正常
4, 查看 ReplicaSet(RS)的运行情况
- [root@andyxu-test ~]# kubectl get rs
- NAME DESIRED CURRENT READY AGE
- MySQL-3238461207 1 1 1 6m
注: 都是 1 表示运行正常
5, 查看 Pod 的运行情况
- [root@andyxu-test ~]# kubectl get pod
- NAME READY STATUS RESTARTS AGE
- MySQL-3238461207-vvwt8 1/1 Running 0 56m
注: READY 的值是 1/1, 并且 STATUS 的值是 Running, 表示运行正常
由于 Pod 的创建需要花费一些时间, 在还没有创建好容器时, STATUS 的状态会是 ContainerCreating, 表示正在创建容器, 这时只需要等待. Pod 创建好后, STATUS 的状态会是 Running, 这时可以通过 docker ps 命令查看容器运行的情况.
6, 查看容器的运行情况
- [root@andyxu-test ~]# docker ps
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- 5252cd76009a MySQL:5.7 "docker-entrypoint..." 55 minutes ago Up 55 minutes k8s_mysql.23f88726_mysql-3238461207-vvwt8_default_72d7bff7-d81c-11e8-a729-000c29dabb02_6b15dcfc
- f026e79ddad9 registry.access.RedHat.com/rhel7/pod-infrastructure:latest "/usr/bin/pod" 55 minutes ago Up 55 minutes k8s_POD.1d520ba5_mysql-3238461207-vvwt8_default_72d7bff7-d81c-11e8-a729-000c29dabb02_668a091e
7, 查看 Pod 里容器的时间, 检查时间是否与本地时间一致
- [root@andyxu-test ~]# kubectl exec MySQL-3238461207-vvwt8 date
- Thu Oct 25 15:06:15 CST 2018
注: exec 后面跟 pod 的名称
8, 创建 MySQL 的 service 定义文件
MySQL-svc.YAML 文件内容如下:
- apiVersion: v1
- kind: Service #表示 Kubernetes Service
- metadata:
- name: MySQL #Service 的名称
- spec:
- ports:
- - port: 3306 #Service 提供服务的端口号
- selector:
- App: MySQL #Service 对应的 Pod 的标签
metadata.name:Service 的服务名称
spec.ports:Service 提供的服务端口号, 对应容器的服务端口号
spec.selector: 确定哪些 Pod 副本 (实例) 对应到此 Service
9, 创建 Service
- [root@andyxu-test ~]# kubectl create -f MySQL-svc.YAML
- service "mysql" created
10, 查看 Service 的运行情况
- [root@andyxu-test ~]# kubectl get svc
- NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- kubernetes 10.254.0.1 <none> 443/TCP 4h
- MySQL 10.254.144.64 <none> 3306/TCP 57s
kubernetes 会给 Service 分配一个 Cluster IP, 这是个虚拟 IP 地址, 此后集群中的其他新创建的 Pod 就可以通过此 Cluster IP + 端口号的方式来连接和访问 MySQL 服务了.
三, 创建并配置 tomcat 容器
1, 创建 tomcat 的 Deployment 定义文件
myweb-dep.YAML 文件的内容如下:
- apiVersion: extensions/v1beta1
- kind: Deployment
- metadata:
- name: myweb
- spec:
- replicas: 1
- selector:
- matchLabels:
- App: myweb
- strategy:
- type: RollingUpdate
- template:
- metadata:
- labels:
- App: myweb
- spec:
- containers:
- - name: myweb
- image: kubeguide/tomcat-App:v1
- volumeMounts:
- - name: time-zone
- mountPath: /etc/localtime
- - name: tomcat-logs
- mountPath: /usr/local/tomcat/logs
- ports:
- - containerPort: 8080
- env:
- - name: MYSQL_SERVICE_HOST
- value: '10.254.144.64' #此处为 MySQL 服务的 Cluster IP
- - name: MYSQL_SERVICE_PORT
- value: '3306'
- volumes:
- - name: time-zone
- hostPath:
- path: /etc/localtime
- - name: tomcat-logs
- hostPath:
- path: /data/tomcat/logs
2, 创建 tomcat 的 deployment,RS,Pod 和容器
- [root@andyxu-test ~]# kubectl create -f myweb-dep.YAML
- deployment "myweb" created
创建过程比较久, 请耐心等待, pod 的 STATUS 状态为 Running 时表示创建成功.
3, 创建 tomcat 的 Service 定义文件
myweb-svc.YAML 文件的内容如下:
- apiVersion: v1
- kind: Service
- metadata:
- name: myweb
- spec:
- type: NodePort
- ports:
- - port: 8080
- nodePort: 30001
- selector:
- App: myweb
此 Service 开启了 NodePort 方式的外网访问模式, 端口为 30001, 此端口会映射到 tomcat 容器的 8080 端口上.
4, 创建 Service
- [root@andyxu-test ~]# kubectl create -f myweb-svc.YAML
- service "myweb" created
5, 查看 Service 的运行情况
- [root@andyxu-test ~]# kubectl get svc
- NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- kubernetes 10.254.0.1 <none> 443/TCP 5h
- MySQL 10.254.144.64 <none> 3306/TCP 24m
- myweb 10.254.246.56 <nodes> 8080:30001/TCP 39s
6, 可使用 curl 命令测试 tomcat 服务是否能正常访问
[root@andyxu-test ~]# curl http://192.168.2.238:30001
四, 通过浏览器访问网页
1, 如果 30001 端口不通的话, 重新启动, 关闭 firewalld 防火墙
- [root@andyxu-test ~]# systemctl start firewalld
- [root@andyxu-test ~]# systemctl stop firewalld
注: 因为 kubernetes 会在 iptables 里添加一些策略, 需要再重新开启关闭防火墙才会关闭掉这些策略.
2, 通过浏览器访问 http://192.168.2.238:30001/demo/
点击 "Add...", 添加一条记录并提交
提交以后, 数据就被写入 MySQL 数据库里了.
3, 登陆 MySQL 数据库验证
- [root@andyxu-test ~]# docker exec -it 5252cd76009a /bin/bash
- root@MySQL-3238461207-vvwt8:/# MySQL -uroot -p123456
- MySQL> use HPE_APP
- MySQL> select * from T_USERS;
我们可以继续研究下这个例子, 比如:
研究 RS,Service 等文件的格式.
熟悉 kubectl 的子命令.
手工停止某个 Service 对应的容器, 观察有什么现象发生.
修改 Deployment 文件, 改变 pod 副本的数量, 重新创建, 观察结果.
此例子来源于《Kubernetes 权威指南(第 2 版)》, 我做了一些修改, 以及报错的处理, 并且使用了 Deployment 来创建.
来源: http://blog.51cto.com/andyxu/2309187