Kubernetes 是目前最主流的开源容器编排技术,用于自动部署,扩展和管理容器化应用程序,其提供应用部署、维护、 扩展机制等一系列完整功能,极大提高了容器集群管理的便捷性。
京东早在2016年年底上线了京东新一代容器引擎平台JDOS2.0,成功从OpenStack切换到Kubernetes技术栈,打造了完整高效的PaaS平台;拥有全球最大规模的Docker集群,容器数量超过20万,节点数超过8000台,集群支撑万亿电商交易,支撑多次6.18和11.11大促的考验。
京东云Kubernetes整合京东云虚拟化、存储和网络能力,提供高性能可伸缩的容器应用管理能力,简化集群的搭建和扩容等工作,让用户专注于容器化的应用的开发与管理。
用户可以在京东云创建一个安全高可用的 Kubernetes 集群,并由京东云完全托管 Kubernetes 服务,并保证集群的稳定性和可靠性。让用户可以方便地在京东云上使用 Kubernetes 管理容器应用。
京东云Kubernetes集群:https://www.jdcloud.com/cn/products/jcs-for-kubernetes
京东云MySQL:https://www.jdcloud.com/cn/products/jcs-for-mysql
本文将使用京东云Kubernetes集群,在京东云VPC内通过Maven及Docker构建SpringBoot镜像,并将镜像部署至Kubernetes,SpringBoot使用京东云MySQL提供稳定可靠的云数据库服务。
本例中的操作均在一个私有网络VPC内,包括kubernetes集群、管理构建节点、Mysql实例:
VPC名称:SprintBoot-K8S
CIDR:10.0.0.0/16
集群配置:
名称:k8s-sprintboot
管理节点CIDR:192.168.0.0/24 (管理节点CIDR不必预先创建,与工作节点CIDR不能重复)
添加可用京东云AccessKey
工作节点配置:
私有网络:使用刚创建的VPC(SprintBoot-K8S)
工作节点CIDR:10.0.0.0/18 (该CIDR在”SprintBoot-K8S” VPC内,k8s会在该CIDR下创建多个子网)
工作节点数量:3
工作节点组:springboot-group-1
控制台上进入kubernetes集群页面:
集群详细信息(服务端点为k8s API Server对外地址):
云主机页面下,可以看到3个工作节点+1个nat节点(nat节点用于k8s工作节点访问外部网络):
Kubernetes在VPC下新建4个子网,分别为:nat、service、pod、node:
SprintBoot-K8S私有网络内新建子网:
CIDR:10.0.64.0/18 (与kubernetes集群子网区分)
子网内新建云主机:
名称:SpringBoot-forbuild
OS:CentOS 7.4
子网选择刚创建的子网
# yum install -y docker
# systemctl start docker
# systemctl enable docker
# docker version
Client:
Version: 1.13.1
API version: 1.26
Package version: docker-1.13.1-74.git6e3bb8e.el7.centos.x86_64
Go version: go1.9.4
Git commit: 6e3bb8e/1.13.1
Built: Tue Aug 21 15:23:37 2018
OS/Arch: linux/amd64
Server:
Version: 1.13.1
API version: 1.26 (minimum version 1.12)
Package version: docker-1.13.1-74.git6e3bb8e.el7.centos.x86_64
Go version: go1.9.4
Git commit: 6e3bb8e/1.13.1
Built: Tue Aug 21 15:23:37 2018
OS/Arch: linux/amd64
Experimental: false
# yum install –y git
# yum install -y maven
# mvn -version
Apache Maven 3.0.5 (Red Hat 3.0.5-17)
Maven home: /usr/share/maven
Java version: 1.8.0_181, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.181-3.b13.el7_5.x86_64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-693.17.1.el7.x86_64", arch: "amd64", family: "unix"
kubectl客户端下载页面:
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG.md
本例中安装kubectl 1.8.12,与集群版本一致,由于云主机无法访问google,可先将kubectl二进制tar包下载至本地,然后上传至云主机:
# ll kubernetes-client-linux-amd64.tar.gz
-rw-r--r-- 1 root root 26148129 Aug 23 11:04 kubernetes-client-linux-amd64.tar.gz
解压:
# tar -xvf kubernetes-client-linux-amd64.tar.gz
将kubectl移动至/usr/local/bin/目录下:
# mv kubernetes/client/bin/kubectl /usr/local/bin/
# source <(kubectl completion bash)
# echo "source <(kubectl completion bash)" >> ~/.bashrc
重新登录shell
切换到k8s集群的客户端配置页面,可按照说明配置kubectl客户端:
将配置信息写入~/.kube/config:
# mkdir ~/.kube
# vim ~/.kube/config
创建新的namespace用于运行Spring应用:
# kubectl create namespace spring-mysql
namespace "spring-mysql" created
# kubectl get namespace
NAME STATUS AGE
default Active 1h
kube-public Active 1h
kube-system Active 1h
libing-test Active 40m
spring-mysql Active 15s
查看版本信息:
# kubectl version
查看3个工作node节点:
# kubectl get node
查看kubernetes集群默认的namespace:
# kubectl get namespace
查看各个组件是否正常运行:
# kubectl get pod -n kube-system
上图看到各个组件均处于running的状态。
本节创建一个简单nginx应用验证kubernetes集群功能,以下操作在管理构建云主机” SpringBoot-forbuild”上操作,测试yaml文件存放于Github:
https://github.com/jcloud-architecture/gs-accessing-data-mysql/tree/master/complete/yaml
# kubectl create namespace libing-test
namespace "libing-test" created
# kubectl create -f https://raw.githubusercontent.com/jcloud-architecture/gs-accessing-data-mysql/master/complete/yaml/nginx-deployment.yaml -n libing-test
deployment "my-nginx" created
# kubectl get pod -n libing-test
# kubectl create -f https://raw.githubusercontent.com/jcloud-architecture/gs-accessing-data-mysql/master/complete/yaml/nginx-svc.yaml -n libing-test
本例中创建的为LoadBalancer类型的service,会自动创建一个负载均衡如下:
负载均衡后端端口为30062(将流量转发至各node节点的30062端口):
Node节点的kube-proxy组件负责将访问30062端口的流量转至Pod的80端口。以下为service的具体配置:
Kubectl也可以查看External IP,为京东云LB的公网IP:
# kubectl get svc -n libing-test
Kubernetes集群测试完毕,应用可正常运行!
本节将在创建京东云Mysql实例,然后通过手动配置Service Endpoint将Mysql服务导入kubernetes集群。
MySQL服务配置信息如下:
VPC:SprintBoot-K8S
子网名称:mysql-forSpring
CIDR:10.0.128.18
配置响应的实例、库、账号、密码:
实例名称:mysqlforspring
库名称:mysqlforspring
账号:mysqlforspring
Kubernetes集群内创建用于访问mysql外部服务的endpoint:
MySQL yaml文件中指定mysql服务的内部IP和端口:
# cat mysql-endpoint.yaml
kind: Endpoints
apiVersion: v1
metadata:
name: mysql
subsets:
- addresses:
- ip: 10.0.128.5
ports:
- port: 3306
创建MySQL endpoint:
# kubectl create -f mysql-endpoint.yaml -n spring-mysql
创建成功:
# kubectl get endpoints -n spring-mysql
创建MySQL service关联上小节的MySQL endpoint:
如下为mysql service的yaml文件:
# cat mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
创建mysql service:
# kubectl create -f mysql-service.yaml -n spring-mysql
查看mysql service:
# kubectl describe svc/mysql -n spring-mysql
上图可以看到service ip为10.0.62.175,且service已经与MySQL外部服务绑定。
下一节Spring应用便通过该Service访问mysql服务。
Spring源码存放在Github:
# git clone https://github.com/jcloud-architecture/gs-accessing-data-mysql.git
Cloning into 'gs-accessing-data-mysql'...
remote: Counting objects: 703, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 703 (delta 4), reused 13 (delta 4), pack-reused 684
Receiving objects: 100% (703/703), 297.47 KiB | 224.00 KiB/s, done.
Resolving deltas: 100% (491/491), done.
更改properties中的jdbc以及mysql用户名密码:
# vim gs-accessing-data-mysql/complete/src/main/resources/application.properties
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:mysql://mysql.spring-mysql.svc.cluster.local:3306/mysqlforspring
spring.datasource.username=mysqlforspring
spring.datasource.password=yourpassword
Kubernetes中service的默认DNS为:
..svc.cluster.local
集群内部可以直接访问service该域名访问后端服务。
进入complete目录:
# cd gs-accessing-data-mysql/complete/
开始构建:
# mvn clean package
Build成功后会在target目录下生成JAR包:
# ls target/
下一步将该Jar包打包进Docker镜像。
创建用于docker build的目录:
# mkdir ~/build
# cp ~/gs-accessing-data-mysql/complete/target/gs-mysql-data-0.1.0.jar ~/build/
# cd ~/build
# ls
gs-mysql-data-0.1.0.jar
build目录下创建Dockerfile:
# vim Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
开始构建:
# docker build -t bingli7/spring-mysql:0823 --build-arg JAR_FILE=gs-mysql-data-0.1.0.jar .
Sending build context to Docker daemon 30.19 MB
Step 1/5 : FROM openjdk:8-jdk-alpine
Trying to pull repository docker.io/library/openjdk ...
8-jdk-alpine: Pulling from docker.io/library/openjdk
8e3ba11ec2a2: Pull complete
311ad0da4533: Pull complete
df312c74ce16: Pull complete
Digest: sha256:1fd5a77d82536c88486e526da26ae79b6cd8a14006eb3da3a25eb8d2d682ccd6
Status: Downloaded newer image for docker.io/openjdk:8-jdk-alpine
---> 5801f7d008e5
Step 2/5 : VOLUME /tmp
---> Running in 17d44204a97c
---> aa1087be0d45
Removing intermediate container 17d44204a97c
Step 3/5 : ARG JAR_FILE
---> Running in 0aec21218c2c
---> 14b6bedd0971
Removing intermediate container 0aec21218c2c
Step 4/5 : COPY ${JAR_FILE} app.jar
---> 6c62bb3a1b28
Removing intermediate container 2ab4e026c801
Step 5/5 : ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar /app.jar
---> Running in 55fdc8c4ee34
---> bad4a64850cf
Removing intermediate container 55fdc8c4ee34
Successfully built bad4a64850cf
构建成功!
注:
Docker build命令中,-t指定了镜像的名字为bingli7/spring-mysql:0823 (bingli7是docker hub账户名,0823是镜像tag)
JAR_FILE=gs-mysql-data-0.1.0.jar表示当前目录下的JAR文件,对应Dockerfile中的JAR_FILE变量
查看镜像:
# docker images
Spring-mysql为刚build成功的镜像,openjdk为build基础镜像。
本例中使用Docker Hub存储镜像。
登录Docker Hub:
# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: bingli7
Password:
Login Succeeded
推送镜像至Docker Hub:
# docker push bingli7/spring-mysql:0823
Push成功!
本节将会使用build成功的镜像在kubernetes集群中部署Spring应用。
Spring deployment Yaml文件:
# vim spring-mysql.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: spring-mysql
spec:
selector:
matchLabels:
run: spring-mysql
replicas: 1
template:
metadata:
labels:
run: spring-mysql
spec:
containers:
- name: spring-mysql
image: bingli7/spring-mysql:0823
ports:
- containerPort: 8080
注:
image: bingli7/spring-mysql:0823为上节推送至docker hub的镜像,kubernetes默认会从docker hub上pull该镜像
部署Spring应用:
# kubectl create -f spring-mysql.yaml -n spring-mysql
deployment "spring-mysql" created
Pod 状态已经running
查看pod的日志:
# kubectl logs pod/spring-mysql-bb4b5db69-f7cp4 -n spring-mysql
Spring应用运行正常!
本节配置LB类型的service,供集群外部用户访问k8s内部的Spring application:
# vim spring-mysql-svc.yaml
kind: Service
apiVersion: v1
metadata:
name: spring-mysql
labels:
run: spring-mysql
spec:
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30066
type: LoadBalancer
selector:
run: spring-mysql
创建service:
# kubectl create -f spring-mysql-svc.yaml -n spring-mysql
service "spring-mysql" created
EXTERNAL-IP为京东云负载均衡公网IP。
插入一条用户数据至mysql:
# curl 'http://116.196.122.119/demo/[email protected]'
Saved
116.196.122.119为spring app的外部访问地址,即LB公网IP。
访问Spring应用:
# curl http://116.196.122.119/demo/all
[{"id":1,"name":"libing","email":"[email protected]"}]
返回用户数据!
或者浏览器访问http://116.196.122.119/demo/all
数据正常返回!
提升spring pod副本数量至3个:
# kubectl scale deployment spring-mysql --replicas=3 -n spring-mysql
deployment "spring-mysql" scaled
Spring-mysql有3个endpoint,ip分别为3个spring pod的IP地址。
现在,访问Spring应用可以负载均衡到3个pod上。
以上。