Kubernetes avec Java, Tomcat et CloudSQL - 2eme partie
Cet article fait suite à Kubernetes avec Java, Tomcat et CloudSQL - 1ere partie qu'il est recommandé de lire en premier.
External configuration support in application
La base de cet article est le projet utilisé dans la 1ere partie, qui va être modifié pour pouvoir utiliser un fichier de configuration externe WebTestApp.properties ainsi qu'utiliser Log4j avec un fichier de configuration log4j.properties externe. Ces fichiers de configuration seront gardés en dehors du war ce qui rendra plus facile la gestion de configurations multiples. (dev, test, prod...)
update Servlet source code to use Log4j and external log4j.properties
public void init(ServletConfig config) throws ServletException {
super.init(config);
boolean log4jfile = false;
// (...)
// configure logging from external file
try {
File linux = new File(Config.CONFIG_LOCATION_PROD+"log4j.properties");
if(linux.exists() && !linux.isDirectory()) {
log4jfile=true;
PropertyConfigurator.configure(Config.CONFIG_LOCATION_PROD+"log4j.properties");
}
} catch(NullPointerException npe) {
log.error("File not found at Prod location!");
}
if(log4jfile!=true) { // then try dev location
try {
File windows = new File(Config.CONFIG_LOCATION_WINDOW+"log4j.properties");
if(windows.exists() && !windows.isDirectory()) {
PropertyConfigurator.configure(Config.CONFIG_LOCATION_WINDOW+"log4j.properties");
}
} catch(NullPointerException npe) {
log.error("File not found at Window location!");
throw new RuntimeException("No configuration file found!");
}
}
// (...)
}
update Servlet source code to retrieve configuration from external file
public void init(ServletConfig config) throws ServletException {
super.init(config);
boolean result = false;
// (...)
// configure application from external file
try {
result = Config.parseConfig(Config.CONFIG_LOCATION_PROD+"webtestapp.properties");
} catch (IOException e) {
log.error("Config File not found at Prod location!");
}
if(result != true) {
try {
result = Config.parseConfig(Config.CONFIG_LOCATION_WINDOW+"webtestapp.properties");
} catch (IOException e) {
log.error("Config File not found at Window location!");
throw new RuntimeException("No Config file found!");
}
}
// (...)
}
Application update with new war version
build and retrieve updated war
...
build new version of Docker image
$ cd webapps-image
$ sudo docker build -t areg/webapps:2 .
Sending build context to Docker daemon 6.56 MBStep 1 : FROM alpine ---> f58f84d16010Step 2 : RUN apk add --no-cache bash ---> Using cache ---> 3364f32f74e3Step 3 : ADD WebTestApp.war webapps/WebTestApp.war ---> 26890218f509Removing intermediate container 5c40c9714b10Step 4 : CMD "tail" "-f" "/dev/null" ---> Running in 9437edc086ce ---> 52de2e6c5a39Removing intermediate container 9437edc086ceSuccessfully built 52de2e6c5a39
tag new version to prepare it for Google Container Registry
$ sudo docker tag areg/webapps:2 gcr.io/$PROJ/webapps:2
check image is ready
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZEareg/webapps 2 52de2e6c5a39 4 minutes ago 9.885 MBgcr.io/xtrav42kub/webapps 2 52de2e6c5a39 4 minutes ago 9.885 MBareg/webapps 1 e65cc1dcc8d1 4 hours ago 9.885 MBgcr.io/xtrav42kub/webapps 1 e65cc1dcc8d1 4 hours ago 9.885 MBtomcat 7 e496879c35a6 3 days ago 357.3 MBareg/tomcat7 1 e496879c35a6 3 days ago 357.3 MBgcr.io/xtrav42kub/tomcat7 1 e496879c35a6 3 days ago 357.3 MBalpine latest f58f84d16010 4 weeks ago 4.803 MB
push image to Google Container Registry
$ gcloud docker -- push gcr.io/$PROJ/webapps:2
The push refers to a repository [gcr.io/xtrav42kub/webapps] (len: 1)52de2e6c5a39: Pushed 26890218f509: Pushed 3364f32f74e3: Image already exists f58f84d16010: Image already exists 2: digest: sha256:e69e0301dbe14ee138bd39cc7994d7098b16d01410590a7afba9c732808e83aa size: 6223
update deployment descriptor to use new image
$ cd ..
$ cp mywebapp-deploy.yaml mywebapp-deploy-2.yaml
$ vi mywebapp-deploy-2.yaml
(...)
spec:
containers:
- image: gcr.io/xtrav42kub/webapps:2
(...)
stop deployment
$ kubectl delete deployment mywebapp-deploy
start new deployment with new deployment descriptor
$ kubectl create -f mywebapp-deploy-2.yaml
External configuration integration with ConfigMap
prepare folder for ConfigMap
$ mkdir config-webtestapp
$ cd config-webtestapp
prepare log4j.properties
$ vi log4j.properties
log4j.rootLogger=TRACE, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%20.20c] - %20.20M(): %m%n
log4j.logger.com.mydomain.webtestapp=TRACE, A1
prepare configuration file webtestapp.properties
$ vi webtestapp.properties
instance=config-master1
databaseurl=jdbc:mysql://YY.YY.YY.YY:3306/testal1?useUnicode=true&characterEncoding=UTF-8
dblogin=root
dbpassword=XXXX
dbdriver=com.mysql.jdbc.Driver
create config map for those files
$ cd ..
$ kubectl create configmap myconfigmap --from-file=config-webtestapp
configmap "myconfigmap" created
check content of configmap
$ kubectl get configmaps myconfigmap -o yaml
apiVersion: v1data: log4j.properties: | log4j.rootLogger=TRACE, A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%20.20c] - %20.20M(): %m%n log4j.logger.com.mydomain.webtestapp=TRACE, A1 webtestapp.properties: | instance=config-master1 databaseurl=jdbc:mysql://YY.YY.YY.YY:3306/testal1?useUnicode=true&characterEncoding=UTF-8 dblogin=root dbpassword=XXXX dbdriver=com.mysql.jdbc.Driverkind: ConfigMapmetadata: creationTimestamp: 2016-11-21T13:58:22Z name: myconfigmap namespace: default resourceVersion: "15973" selfLink: /api/v1/namespaces/default/configmaps/myconfigmap uid: 90e1c97f-aff2-11e6-8ca6-42010a80012b
update deployment descriptor to use the configmap
$ vi mywebapp-deploy-2.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mywebapp-deploy
spec:
replicas: 1
template:
metadata:
labels:
app: mywebapp
spec:
containers:
- image: gcr.io/xtrav42kub/webapps:1
name: webapps
lifecycle:
postStart:
exec:
command:
- "sh"
- "-c"
- >
touch /var/log/preparation_start ;
/bin/cp -rf /webapps/* /apps/
volumeMounts:
- mountPath: /apps
name: app-volume
- image: gcr.io/xtrav42kub/tomcat7:1
name: tomcat
volumeMounts:
- mountPath: /usr/local/tomcat/webapps
name: app-volume
- mountPath: /config/WebTestApp
name: config-volume
ports:
- containerPort: 8080
volumes:
- name: app-volume
emptyDir: {}
- name: config-volume
configMap:
name: myconfigmap
create deployment with updated description
$ kubectl create -f mywebapp-deploy-2.yaml
deployment "mywebapp-deploy" created
identify running pod
$ kubectl get pods
NAME READY STATUS RESTARTS AGEmywebapp-deploy-1721315703-p9glh 2/2 Running 0 9m
connect to a bash shell on tomcat container on running pod
$ kubectl exec -it mywebapp-deploy-1721315703-p9glh bash -c tomcat
root@mywebapp-deploy-1721315703-p9glh:/usr/local/tomcat#
(in container) verify content of config folder
$ ls /config/WebTestApp/
log4j.properties webtestapp.properties
(in container) verify content of config file
$ cat /config/WebTestApp/webtestapp.properties
instance=config-master1databaseurl=jdbc:mysql://YY.YY.YY.YY:3306/testal1?useUnicode=true&characterEncoding=UTF-8dblogin=rootdbpassword=XXXXdbdriver=com.mysql.jdbc.Driver
create service
$ kubectl create -f mywebapp-service.yaml
service "mywebapp-service" created
retrieve service external ip address and wait a bit for pod to be fully restarted
$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes 10.3.240.1 <none> 443/TCP 3hmywebapp-service 10.3.252.113 104.198.250.211 8080/TCP 1m
test new service from web browser at http://104.198.250.211:8080/WebTestApp/front?action=status
Ressources requests and limitations
update deployment description to request and limit ressources used by pods
$ cp mywebapp-deploy-2.yaml mywebapp-deploy-3.yaml
$ vi mywebapp-deploy-3.yaml
(...)
spec:
containers:
- image: gcr.io/xtrav42kub/webapps:2
name: webapps
resources:
requests:
cpu: 10m
(...)
- image: gcr.io/xtrav42kub/tomcat7:1
name: tomcat
resources:
limits:
cpu: 250m
memory: 250Mi
(...)
start new deployment
$ kubectl delete deployment mywebapp-deploy
deployment "mywebapp-deploy" deleted$ kubectl create -f mywebapp-deploy-3.yaml
deployment "mywebapp-deploy" created