Description of parameters
The replacement parameters used in the following are described:
${env}: environment variables, which describe the development environment, test environment, and use namespaces to distinguish environments on k8s, so first you need to create a namespace: kubectl create namespace ${env}, namespace names can only be alphabetical data connectors (-);
${group}: project group name, or product line name;
${appName}: application name;
${version}: application version;
${repository}: docker repository
Deployment process description
Step 1: Generate a specific Docker file
The Dockerfile template is as follows:
FROM ${repository}/xxxx/base:v4.0 MAINTAINER xxxx@xxxx.cn COPY ./ROOT.war /root/tomcat/webapps CMD ["/root/init.sh"]
Explain:
- The application Dockerfile inherits the basic image, copies the war package to tomcat's webapps directory, and sets the startup command to be init.sh script.
- Basic Mirror: Use Minimum linux Version: Alpine, JRE Dependent on glibc: bash, glibc, jre, tomcat need to be added on the basis of from alpine. The working directory of Tomcat is / root/tomcat. See the annex section for details.
- Applications can also mount ROOT onto the basic image container using shared read-write volumes instead of creating mirrors. This practice is not recommended.
Step 2: Create a mirror
docker rmi -f ${repository}/${group}/${appName}:${version} docker build -t ${repository}/${group}/${appName}:${version} --no-cache -f Dockerfile-${appName}-${env} .
Delete existing mirrors and create new ones.
The name of the image created: ${repository}/${group}/${appName}:${version}
Step 3: Submit the mirror
docker login ${repository} -u admin -p password docker push ${repository}/${group}/${appName}:${version}
Login to the warehouse and submit the image.
Step 4: Allocate application ports
The ports of applications are managed by configMap. When ports are needed, configMap is exported to get the application ports. The configMap file template is as follows:
apiVersion: v1 kind: ConfigMap metadata: name: ${env}-env namespace: ${env} data: ${appName1}.applicationName: xxxxxx ${appName1}.port: "30001" ${appName2}.applicationName: yyyyyy ${appName2}.port: "30101"
Explain:
Environment Name: corresponds to the environment Name in the original setenv.sh;
ZookeeperUrl: corresponding to the original setenv.zookeeperUrl;
${appName1}: Apply identifier, cannot use underscore;
ApplicationName: ${appName1} setenv.applicationName: corresponding to the original application ${appName1} setenv.applicationName;
${appName1}.port: The tomcat port assigned to the application ${appName1} where the port must be double quoted;
Create configMap: kubectl create -- save-config-f configMap - ${env}. yaml
If configMap already exists: there are two ways to upgrade
1) recreate: delete configMap and create it again;
2) rolling upgrade: kubectl apply-f configMap - ${env}.yaml
Step 5: Define deployment,service
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: ${appName} namespace: ${env} labels: app: ${appName} spec: replicas: 1 selector: matchLabels: app: ${appName} template: metadata: labels: app: ${appName} spec: containers: - name: ${appName} imagePullPolicy: Always image: ${repository}/${group}/${appName}:${version} env: - name: port valueFrom: configMapKeyRef: name: ${env}-env key: ${appName}.port ports: - containerPort: %port% volumeMounts: - mountPath: "/pv" name: hp-${appName}-${env} volumes: - name: hp-${appName}-${env} hostPath: path: /data/k8s_volume/${appName}-${env} tolerations: - key: "CriticalAddonsOnly" operator: "Exists"
Explain:
- The ports of tomcat, pod, service and node need to be consistent before they can be accessed. Why is it not clear? Service port limit is 30000-80000, node port limit is 0-32767, so configurable port range is 30000-32767.
- spec.selector is used to specify label selector and delineate the pod range managed by Deployment. If specified, the. spec.selector must match. spec.template.metadata.labels, otherwise it will be rejected by the API.
- namespace: Use ${env} to partition
- The environment variables that set up the pod container are: port. They are all obtained from the configMap of ${env}-env
- Image Pull Policy is set to Always, always pulling mirrors from the warehouse
- Persistent volume: The data volume used by pod is set to read and write shared nfs persistent volume. Detailed definitions can be found in the annex section.
apiVersion: v1 kind: Service metadata: name: ${appName} namespace: ${env} labels: app: ${appName} spec: type: NodePort selector: app: ${appName} ports: - port: %port% targetPort: %port% nodePort: %port%
Explain:
- type: Use NodePort: Assign a virtual IP accessible within the cluster to the service and bind a port on the node so that the service can be accessed through <NodeIP>: NodePort.
- Selector: Use selector to select pod to generate endpoint.
- port: port for service monitoring
- targetPort: Port that needs to be forwarded to the back-end pod
- nodePort: Port number of physical machine node
Step 6: Create deployment,service
port=`kubectl get configmap ${env}-env -n ${env} -o yaml|grep ${appName}.port|awk -F '"' '{print $2}'` sed -i "s/%port%/$port/g" ${appName}-${env}.yaml kubectl create --save-config -f ${appName}-${env}.yaml
Get the port from configmap, replace the placeholder in the yaml file, and create the resources defined in the yaml file.
Upgrade process description
Two ways:
1) recreate: delete the application pod, deployment automatically retrieves the mirror to create a new podkubectl delete pod name - n ${env};
2) rolling upgrade: kubectl apply-f ${appName} - ${env}. yaml
Basic Mirror Dockerfile
FROM alpine:latest MAINTAINER xxx@xx.cn ENV tomcat_home=/root/tomcat \ JAVA_HOME=/root/jre1.7.0_80 \ PATH=$JAVA_HOME/bin:$PATH \ LANG=zh_CN.UTF-8 \ TZ="Asia/Shanghai" \ GLIBC_PKG_VERSION=2.23-r1 ADD ./jre-7u80-linux-x64.gz /root COPY ./tomcat $tomcat_home COPY ./init.sh /root WORKDIR /tmp RUN chmod 775 /root/init.sh && \ echo "https://mirrors.aliyun.com/alpine/v3.6/main">/etc/apk/repositories && \ apk add --no-cache --update-cache wget ca-certificates bash bash-doc bash-completion && \ wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://raw.githubusercontent.com/sgerrand/alpine-pkg-glibc/master/sgerrand.rsa.pub && \ wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_PKG_VERSION}/glibc-${GLIBC_PKG_VERSION}.apk && \ wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_PKG_VERSION}/glibc-bin-${GLIBC_PKG_VERSION}.apk && \ wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_PKG_VERSION}/glibc-i18n-${GLIBC_PKG_VERSION}.apk && \ apk add glibc-${GLIBC_PKG_VERSION}.apk glibc-bin-${GLIBC_PKG_VERSION}.apk glibc-i18n-${GLIBC_PKG_VERSION}.apk && \ apk del curl ca-certificates && \ rm -rf /tmp/* /var/cache/apk/*
init.sh startup script
#!/bin/bash #sed -i 's/autoDeploy="true">/autoDeploy="true"><Context path="" docBase="\/pv\/war\/ROOT.war"\/>/' $tomcat_home/conf/server.xml sed -i "s/8080/$port/" $tomcat_home/conf/server.xml sh $tomcat_home/bin/startup.sh tail -F $tomcat_home/logs/catalina.out
Persistent Volume Definition
apiVersion: v1 kind: PersistentVolume metadata: name: pv-nfs namespace: ${env} spec: capacity: storage: 50Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain nfs: path: /data/k8s_volume server: 192.168.0.1 --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pv-nfs namespace: ${env} spec: accessModes: - ReadWriteMany resources: requests: storage: 50Gi
Best Practices
1) ENV RUN Writes in a New Line
2) CMD is recommended, followed by ENTRYPOINT
3) Export compression layer:
docker run --name demo base:v3.0 echo ForExport docker export --output base4.0.tar demo docker rm demo docker import base4.0.tar base:v4.0
4)ONBUILD
5) docker history view mirror layer
6). dockerignore ignores files
7) Using chmod-R 775 directory without compression, the final image will be very large
Pit
- The parameters in the parameterized construction of jenkins are similar to the naming specifications of the general parameters. You can't use the ${} reference to replace the $in the shell script, and you can create another parameter with the same name.
- Container created by docker default user root
- Create mirror ADD command error reporting: Forbidden path outside the build context:..
- docker restart, kubelet also needs to restart
- COPY. / Tomcat / root / Tomcat Dockerfile COPY,
- data source rejected establishment of connection message from server too manay connections
- executable file not found"and"no such file: shell return problem written under windows" http://www.linuxidc.com/Linux/2011-09/42618.htm
Relevant orders
1) Building image from Dockerfile:
docker build -t xxxxxl:v1.0.002 -f Dockerfile-xxxxx .
2) Run image to generate container:
docker run -d -p 30101:30101 --name xxxxx xxxx:v1.0.002
3) Interacting with container:
docker exec -it xxxxx /bin/bash