说明
我们通过一个简单的示例来说明如何在Kubernets中部署一个应用,
- 一个Spring Boot项目提供数据库的增删改查操作
- 一个Mysql数据库持久化数据
通过Eclipse构建一个Spring Boot项目以下简称demo,其中连接mysql的property文件application-k8s.properties内容如下:
- spring.datasource.url=jdbc:mysql://${MYSQL_SERVICE_HOST:127.0.0.1}:${MYSQL_SERVICE_PORT:3306}/${MYSQL_DATABASE:demo}
- spring.datasource.username=${MYSQL_ROOT_USER:root}
- spring.datasource.password=${MYSQL_ROOT_PASSWORD:123456}
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
-
- spring.jpa.database = MYSQL
- # Show or not log for each sql query
- spring.jpa.show-sql = true
- # Hibernate ddl auto (create, create-drop, update)
- spring.jpa.hibernate.ddl-auto = update
我们通过环境变量来指定数据库的连接参数,其中:
- MYSQL_SERVICE_HOST:mysql的hostname或者IP地址
- MYSQL_SERVICE_PORT:mysql的端口号
- MYSQL_DATABASE:连接mysql的数据库名
- MYSQL_ROOT_USER:mysql的root用户名
- MYSQL_ROOT_PASSWORD:mysql的root用户名密码
将demo打包成jar文件,并且用Dockerfile制作成Docker Image上传到私有Registry。
打包jar文件
- mvn package -Dmaven.test.skip=true
- INFO] Scanning for projects...
- [INFO]
- [INFO] --------------------------< com.example:demo >--------------------------
- [INFO] Building demo 0.0.1
- [INFO] --------------------------------[ jar ]---------------------------------
- [INFO]
- [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ demo ---
- [INFO] Using 'UTF-8' encoding to copy filtered resources.
- [INFO] Copying 4 resources
- [INFO] Copying 0 resource
- [INFO]
- [INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ demo ---
- [INFO] Nothing to compile - all classes are up to date
- [INFO]
- [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ demo ---
- [INFO] Not copying test resources
- [INFO]
- [INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ demo ---
- [INFO] Not compiling test sources
- [INFO]
- [INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ demo ---
- [INFO] Tests are skipped.
- [INFO]
- [INFO] --- maven-jar-plugin:3.1.1:jar (default-jar) @ demo ---
- [INFO] Building jar: /Users/xiaobaoqiang/workspace/demo/spring-boot/target/demo.jar
- [INFO]
- [INFO] --- spring-boot-maven-plugin:2.1.3.RELEASE:repackage (repackage) @ demo ---
- [INFO] Replacing main artifact with repackaged archive
- [INFO] ------------------------------------------------------------------------
- [INFO] BUILD SUCCESS
- [INFO] ------------------------------------------------------------------------
- [INFO] Total time: 1.731 s
- [INFO] Finished at: 2019-03-31T12:33:52+08:00
- [INFO] ------------------------------------------------------------------------
Dockerfile如下:
- # base image
- FROM daocloud.io/java:8
-
- # MAINTAINER
- MAINTAINER xiaobaoqiang@163.com
-
- # add demo.jar to docker tmp folder
- ADD ./demo.jar /tmp
-
- # run demo.jar package
- CMD ["java", "-jar", "/tmp/demo.jar"]
-
- EXPOSE 9999
制作Docker镜像
- docker build -t 10.0.0.10:5000/app/demo:v2.0 .
- Sending build context to Docker daemon 44.18 MB
- Step 1/5 : FROM daocloud.io/java:8
- ---> d23bdf5b1b1b
- Step 2/5 : MAINTAINER xiaobaoqiang@163.com
- ---> Using cache
- ---> 6a8e7ffcb8b7
- Step 3/5 : ADD ./demo.jar /tmp
- ---> 11bc5f618c77
- Removing intermediate container c3942d277805
- Step 4/5 : CMD java -jar /tmp/demo.jar
- ---> Running in f877685bb056
- ---> cb08fcc6b0a1
- Removing intermediate container f877685bb056
- Step 5/5 : EXPOSE 9999
- ---> Running in 86a145142954
- ---> 189f73beb27a
- Removing intermediate container 86a145142954
- Successfully built 189f73beb27a
查看Docker镜像
- docker images
- REPOSITORY TAG IMAGE ID CREATED SIZE
- 10.0.0.10:5000/app/demo v2.0 189f73beb27a About an hour ago 687 MB
将制作好的Docker镜像push到私有Registry
- docker push 10.0.0.10:5000/app/demo:v2.0
- The push refers to a repository [10.0.0.10:5000/app/demo]
- 6a6b9dbfc663: Pushed
- 35c20f26d188: Pushed
- c3fe59dd9556: Pushed
- 6ed1a81ba5b6: Pushed
- a3483ce177ce: Pushed
- ce6c8756685b: Pushed
- 30339f20ced0: Pushed
- 0eb22bfb707d: Pushed
- a2ae92ffcd29: Pushed
- v2.0: digest: sha256:7296321564a7ace0bf1f2e8099fb7e0e01610efec5e1d1fec0c877b236bc0f5f size: 2212
到此,我们的demo镜像已经准备就绪,下面开始准备mysql镜像。
由于国外的Docker Hub网速比较慢,我们从国内的Docker Hub拉取一个mysql的镜像到本地
- docker pull daocloud.io/library/mysql:5.7.4
将mysql镜像打tag,并且push到我们的私有Registry
- docker tag daocloud.io/library/mysql:5.7.4 10.0.0.10:5000/library/mysql:5.7.4
- docker push 10.0.0.10:5000/library/mysql:5.7.4
- The push refers to a repository [10.0.0.10:5000/library/mysql]
- 5f70bf18a086: Pushed
- 903c114b758c: Pushed
- c8c909bc9ac1: Pushed
- 6f19f89d53b4: Pushed
- 6e82deab235b: Pushed
- ca60b5cb617c: Pushed
- ac906c9ec95d: Pushed
- 4c816744690c: Pushed
- 5.7.4: digest: sha256:afe1630e8c9bd318a5e72b2536c2daacb96b8135cc2c6d3465262b5c7b7d1831 size: 3846
到此,我们mysql的镜像也准备就绪,下面开始部署我们的demo应用和mysql
创建mysql的部署yaml文件mysql-deployment.yaml
- apiVersion: v1
- kind: Service
- metadata:
- name: mysql
- labels:
- app: mysql
- spec:
- ports:
- - port: 3306
- selector:
- app: mysql
- clusterIP: None
- ---
- apiVersion: apps/v1 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1
- kind: Deployment
- metadata:
- name: mysql
- labels:
- app: mysql
- spec:
- selector:
- matchLabels:
- app: mysql
- template:
- metadata:
- labels:
- app: mysql
- spec:
- containers:
- - image: 10.0.0.10:5000/library/mysql:5.7.4
- name: mysql
- env:
- - name: MYSQL_ROOT_PASSWORD
- value: "123456"
- - name: MYSQL_DATABASE
- value: "demo"
- livenessProbe:
- tcpSocket:
- port: 3306
- ports:
- - containerPort: 3306
- name: mysql
-
通过环境变量初始化了一些参数:
- MYSQL_ROOT_PASSWORD为mysql的root密码
- MYSQL_DATABASE为mysql启动后默认创建的数据库
创建demo应用部署的yaml文件demo-mysql-k8s.yaml
- # ------------------- Demo Deployment ------------------- #
- kind: Deployment
- apiVersion: apps/v1
- metadata:
- labels:
- name: demo
- name: demo
- spec:
- selector:
- matchLabels:
- app: demo
- template:
- metadata:
- labels:
- app: demo
- spec:
- containers:
- - name: demo
- image: 10.0.0.10:5000/app/demo:v2.0
- ports:
- - containerPort: 9999
- protocol: TCP
- env:
- - name: MYSQL_SERVICE_HOST
- value: '172.18.45.2'
- - name: MYSQL_SERVICE_PORT
- value: "3306"
- - name: MYSQL_DATABASE
- value: "demo"
- - name: MYSQL_ROOT_USER
- value: "root"
- - name: MYSQL_ROOT_PASSWORD
- value: "123456"
- livenessProbe:
- httpGet:
- scheme: HTTP
- path: /service/v1/demo
- port: 9999
- initialDelaySeconds: 30
- timeoutSeconds: 30
- ---
- # ------------------- Demo Service ------------------- #
-
- kind: Service
- apiVersion: v1
- metadata:
- labels:
- name: demo
- name: demo
- spec:
- ports:
- - port: 9900
- targetPort: 9999
- selector:
- app: demo
通过环境变量初始化了一些参数,这些参数与application-k8s.properties中的环境变量名对应,其中MYSQL_SERVICE_HOST是mysql部署后的enpoint IP地址。
通过kubectl命令行开始部署
- kubectl apply -f mysql-deployment.yaml
- service/mysql created
- deployment.apps/mysql created
查看mysql的endpoint IP地址
- kubectl get service
- NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- kubernetes ClusterIP 172.10.12.1 <none> 443/TCP 63d
- mysql ClusterIP None <none> 3306/TCP 121m
-
- kubectl describe service mysql
- Name: mysql
- Namespace: default
- Labels: app=mysql
- Annotations: kubectl.kubernetes.io/last-applied-configuration:
- {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"mysql"},"name":"mysql","namespace":"default"},"spec":{"c...
- Selector: app=mysql
- Type: ClusterIP
- IP: None
- Port: <unset> 3306/TCP
- TargetPort: 3306/TCP
- Endpoints: 172.18.45.2:3306
- Session Affinity: None
- Events: <none>
-
可以看到mysql的enpoint IP地址是172.18.45.2,端口号是3306。
部署demo应用
- kubectl apply -f demo-mysql-k8s.yaml
- deployment.apps/demo created
- service/demo created
-
- kubectl get pods
- NAME READY STATUS RESTARTS AGE
- demo-d4cd5bfdd-8qpfw 1/1 Running 0 3s
- mysql-6f76465564-j8dq2 1/1 Running 0 60m
查看demo启动的日志
- kubectl logs demo-d4cd5bfdd-8qpfw
-
- . ____ _ __ _ _
- /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
- ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/ ___)| |_)| | | | | || (_| | ) ) ) )
- ' |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot :: (v2.1.3.RELEASE)
-
- 2019-03-31 03:55:08.236 INFO 1 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication v0.0.1 on demo-d4cd5bfdd-8qpfw with PID 1 (/tmp/demo.jar started by root in /)
- 2019-03-31 03:55:08.245 INFO 1 --- [ main] com.example.demo.DemoApplication : The following profiles are active: k8s
- 2019-03-31 03:55:09.149 INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
- 2019-03-31 03:55:09.204 INFO 1 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 51ms. Found 1 repository interfaces.
- 2019-03-31 03:55:09.516 INFO 1 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$eb5e36c] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2019-03-31 03:55:09.782 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 9999 (http)
- 2019-03-31 03:55:09.807 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
- 2019-03-31 03:55:09.807 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.16]
- 2019-03-31 03:55:09.814 INFO 1 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib]
- 2019-03-31 03:55:09.881 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
- 2019-03-31 03:55:09.881 INFO 1 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1593 ms
- 2019-03-31 03:55:10.129 INFO 1 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
- name: default
- ...]
- 2019-03-31 03:55:10.179 INFO 1 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.3.7.Final}
- 2019-03-31 03:55:10.180 INFO 1 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
- 2019-03-31 03:55:10.284 INFO 1 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
- 2019-03-31 03:55:10.444 INFO 1 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
- 2019-03-31 03:55:20.542 INFO 1 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
- 2019-03-31 03:55:20.551 INFO 1 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
- Hibernate: create table demo_users (id integer not null, birth_day datetime, create_date datetime, email varchar(255), name varchar(255), sex integer, primary key (id)) engine=MyISAM
- Hibernate: create table hibernate_sequence (next_val bigint) engine=MyISAM
- Hibernate: insert into hibernate_sequence values ( 1 )
- 2019-03-31 03:55:20.984 INFO 1 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
- 2019-03-31 03:55:21.315 WARN 1 --- [ main] aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
- 2019-03-31 03:55:21.408 INFO 1 --- [ main] pertySourcedRequestMappingHandlerMapping : Mapped URL path [/v2/api-docs] onto method [public org.springframework.http.ResponseEntity<springfox.documentation.spring.web.json.Json> springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation(java.lang.String,javax.servlet.http.HttpServletRequest)]
- 2019-03-31 03:55:21.504 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
- 2019-03-31 03:55:21.801 INFO 1 --- [ main] d.s.w.p.DocumentationPluginsBootstrapper : Context refreshed
- 2019-03-31 03:55:21.821 INFO 1 --- [ main] d.s.w.p.DocumentationPluginsBootstrapper : Found 1 custom documentation plugin(s)
- 2019-03-31 03:55:21.844 INFO 1 --- [ main] s.d.s.w.s.ApiListingReferenceScanner : Scanning for api listing references
- 2019-03-31 03:55:22.118 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9999 (http) with context path ''
- 2019-03-31 03:55:22.119 INFO 1 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 14.323 seconds (JVM running for 14.62)
通过日志可以看到我们的demo应用已经连接到mysql数据库,我们的demo应用启动正常。
验证
通过Kubernetes的proxy访问我们的demo的health check
- kubectl proxy --address='0.0.0.0' --disable-filter=true &
-
- curl http://10.0.0.10:8001/api/v1/namespaces/default/services/demo/proxy/service/v1/demo
- {"author":"xiaobaoqiang","title":"this is a demo","version":"1.0"}
通过restful api向数据库写入测试数据
- curl -X POST "http://10.0.0.10:8001/api/v1/namespaces/default/services/demo/proxy/service/v1/user" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"birthDay\": \"2019-03-31T04:03:43.259Z\", \"createDate\": \"2019-03-31T04:03:43.259Z\", \"email\": \"A1@test.com\", \"name\": \"A1\", \"sex\": 0}"
- success
-
- curl -X POST "http://10.0.0.10:8001/api/v1/namespaces/default/services/demo/proxy/service/v1/user" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"birthDay\": \"2019-03-31T04:03:43.259Z\", \"createDate\": \"2019-03-31T04:03:43.259Z\", \"email\": \"B2@test.com\", \"name\": \"B2\", \"sex\": 1}"
- success
通过restful api查询刚才写入的数据
- curl -X GET "http://10.0.0.10:8001/api/v1/namespaces/default/services/demo/proxy/service/v1/users" -H "accept: application/json"
- [{"id":1,"name":"A1","email":"A1@test.com","sex":0,"birthDay":"2019-03-31T04:03:43.000+0000","createDate":"2019-03-31T04:03:43.000+0000"},{"id":2,"name":"B2","email":"B2@test.com","sex":1,"birthDay":"2019-03-31T04:03:43.000+0000","createDate":"2019-03-31T04:03:43.000+0000"}]
可以看到已经查询到刚才写入的测试数据。
通过命令行查看数据库的数据
- kubectl get pod
- NAME READY STATUS RESTARTS AGE
- demo-d4cd5bfdd-8qpfw 1/1 Running 0 7m54s
- mysql-6f76465564-j8dq2 1/1 Running 0 67m
-
- kubectl exec -it mysql-6f76465564-j8dq2 bash
- root@mysql-6f76465564-j8dq2:/usr/local/mysql# mysql -u root -p
- Enter password:
- Welcome to the MySQL monitor. Commands end with ; or \g.
- Your MySQL connection id is 422
- Server version: 5.7.4-m14 MySQL Community Server (GPL)
-
- Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
-
- Oracle is a registered trademark of Oracle Corporation and/or its
- affiliates. Other names may be trademarks of their respective
- owners.
-
- Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
-
- mysql>
- mysql> show databases;
- +--------------------+
- | Database |
- +--------------------+
- | information_schema |
- | demo |
- | mysql |
- | performance_schema |
- +--------------------+
- 4 rows in set (0.00 sec)
-
- mysql> use demo;
- Reading table information for completion of table and column names
- You can turn off this feature to get a quicker startup with -A
-
- Database changed
- mysql> show tables;
- +--------------------+
- | Tables_in_demo |
- +--------------------+
- | demo_users |
- | hibernate_sequence |
- +--------------------+
- 2 rows in set (0.00 sec)
-
- mysql> select * from demo_users;
- +----+---------------------+---------------------+-------------+------+------+
- | id | birth_day | create_date | email | name | sex |
- +----+---------------------+---------------------+-------------+------+------+
- | 1 | 2019-03-31 04:03:43 | 2019-03-31 04:03:43 | A1@test.com | A1 | 0 |
- | 2 | 2019-03-31 04:03:43 | 2019-03-31 04:03:43 | B2@test.com | B2 | 1 |
- +----+---------------------+---------------------+-------------+------+------+
- 2 rows in set (0.00 sec)
通过mysql命令行我们可以看到刚才的测试数据已经保存到数据库中。