Dockerfile image construction practice

Image production specification

First create the most common layer, and each subsequent image depends on the previous parent image.

Build images hierarchically and deploy tomcat high availability


tomcat1, nginx1, haproxy1 and keepalived1 are deployed on the 10.0.0.51 node
tomcat2, nginx2, haproxy2 and keepalived2 are deployed on the 10.0.0.52 node
Image construction is mainly performed at node 51.

1. Create a basic CentOS base image

1.1 create image classification directory structure

$ mkdir /opt/dockerfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,redhat}} -pv

1.2 write CentOS base image dockerfile.

$ cd /opt/dockerfile/system/centos
$ mkdir 7.9 && cd 7.9
$ vim Dockerfile
FROM centos:7.9.2009
LABEL author=LiangDong
RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm \
        && yum update -y \
        && yum install -y vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop \
        && groupadd -g 2021 maple \
       && useradd -u 2021 -g 2021 maple

1.3 write the build command to sh to facilitate subsequent mirroring.

$ cat build-command.sh 
#!/bin/bash
docker build -t harbor.maple.com/oss/centos-base:v7.9.2009 .

1.4 build image and test

$ bash build-command.sh
$ docker run -it --rm  harbor.maple.com/oss/centos-base:v7.9.2009 bash
# Check whether the user is created and whether there are commands such as vim

2. Build jdk8 image from CentOS base image

2.1 upload jdk8u291 package

$ cd /opt/dockerfile/web/jdk
$ mkdir jdk8u291 && cd jdk8u291
# Upload jdk8u291 package
$ ls
jdk-8u291-linux-x64.tar.gz

2.2 writing jdk Dockerfile

$ vim Dockerfile 
FROM harbor.maple.com/oss/centos-base:v7.9.2009
MAINTAINER "LiangDong 395539184@qq.com"
ADD jdk-8u291-linux-x64.tar.gz /usr/local/src/
RUN ln -s /usr/local/src/jdk1.8.0_291 /usr/local/jdk \
    && echo "export JAVA_HOME=/usr/local/jdk" > /etc/profile.d/jdk.sh \
    && echo "export JRE_HOME=\$JAVA_HOME/jre" >> /etc/profile.d/jdk.sh \
    && echo "export CLASSPATH=\$JAVA_HOME/lib/:\$JRE_HOME/lib/" >> /etc/profile.d/jdk.sh \
    && echo "export PATH=\$PATH:\$JAVA_HOME/bin" >> /etc/profile.d/jdk.sh \
    && source /etc/profile.d/jdk.sh \
    && rm -rf /etc/localtime \
    && ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

2.3 build and test run

$ ls
build-command.sh  Dockerfile  jdk-8u291-linux-x64.tar.gz
$ bash build-command.sh
$ docker run -it --rm  harbor.maple.com/oss/centos-base-jdk:v1.8.291 bash
# Test whether the date is consistent with the local time zone
# Test whether the root user has java environment variables and can execute Java commands
# Test whether the maple user has java environment variables and can execute Java commands

3. Build tomcat8 image based on jdk8 image

3.1 uploading tomcat package

$ cd /opt/dockerfile/web/tomcat/8.5.64
$ ls
apache-tomcat-8.5.64.tar.gz  build-command.sh  Dockerfile

3.2 create Dockerfile of tomcat

$ cat Dockerfile 
FROM harbor.maple.com/oss/centos-base-jdk:v1.8.291
LABEL author="LiangDong 395539184@qq.com"
ADD apache-tomcat-8.5.64.tar.gz /apps/
RUN ln -s /apps/apache-tomcat-8.5.64 /apps/tomcat

3.3 build and test

$ bash build-command.sh
$ docker run -it --rm -p 8080:8080 harbor.maple.com/oss/tomcat:v8.5.64 bash
# /apps/tomcat/bin/catalina.sh start 
# Page access 8080 test

4. Build business image based on tomcat8 image 1

4.1 preparation of configuration files and test page files

$ cd /opt/dockerfile/web/tomcat/myapp1
$ mkdir myapp1
# Prepare page test file
$ echo "<h1>tomcat myapp1</h1>" > myapp1/index.jsp  
$  tar cvf myapp1.tar.gz myapp1/
$  rm -rf myapp1
# Prepare the tomcat configuration file and modify the tomcat project directory
$ docker run -it --rm -p 8080:8080 harbor.maple.com/oss/tomcat:v8.5.64 bash
# Another terminal performs replication
docker cp 9070a1b76dce:/apps/tomcat/conf/server.xml .

# Modify the tomcat project deployment directory to / data/tomcat/webapps
# Modification does not automatically decompress and deploy, which is easy to attack.
vim server.xml
<Host name="localhost"  appBase="/data/tomcat/webapps" unpackWARs="false" autoDeploy="false">

4.2 prepare the tomcat running script so that the tomcat service is not a process with container PID 1.

$ vim run_tomcat.sh
#!/bin/bash
echo "nameserver 223.5.5.5" > /etc/resolv.conf
# Avoid running tomcat as root
su - maple -c "/apps/tomcat/bin/catalina.sh start"
su - maple -c "tail -f /etc/hosts"

$ chmod +x run_tomcat.sh # needs execution permission, otherwise the script cannot be executed in the container

4.3 write Dockerfile file of myapp1

$ vim Dockerfile 
FROM harbor.maple.com/oss/tomcat:v8.5.64
ENV TOMCAT_HOME /apps/tomcat
COPY server.xml $TOMCAT_HOME/conf/server.xml
COPY run_tomcat.sh $TOMCAT_HOME/bin/
ADD myapp1.tar.gz /data/tomcat/webapps/
RUN chown -R maple.maple $TOMCAT_HOME/ \
    && chown -R maple.maple /data/tomcat
CMD ["/bin/bash","-c","$TOMCAT_HOME/bin/run_tomcat.sh"]

be careful:

	# The following chown command failed to be modified, but it is strange to modify / data/tomcat
	chown -R maple.maple $TOMCAT_HOME
	#Successfully added a / modifiable permission
	chown -R maple.maple $TOMCAT_HOME/

4.4 build and test

$ bash build-command.sh 
$ docker run -it --rm -p 8080:8080 harbor.maple.com/oss/tomcat-myapp1:v1

5. Create business image 2

$ cd /opt/dockerfile/web/tomcat
$ cp myapp1 -r myapp2
$ cd myapp2
# Modify build command
$ vim build-command.sh
docker build -t harbor.maple.com/oss/tomcat-myapp2:v1 .
# Modify test page content
$ tar xf myapp1.tar.gz
$ vim myapp1/index.jsp
<h1>tomcat myapp2</h1>
$ tar cf myapp1.tar.gz myapp1
$ rm -rf myapp1

# structure
$ bash build-command.sh 
# Run test
$ docker run -it --rm -p 8080:8080 harbor.maple.com/oss/tomcat-myapp2:v1


Import to another docker host

$ docker save harbor.maple.com/oss/tomcat-myapp2 > myapp2.tar
$ scp myapp2.tar 10.0.0.52:/home/maple/

Another host is loaded and running

$ docker load -i myapp2.tar 
$ docker run -it --rm -p 8080:8080 harbor.maple.com/oss/tomcat-myapp2:v1

6. Create nginx image

6.1 first build a test nginx to obtain nginx Conf configuration file

$ cd /opt/dockerfile/web/nginx
$ ls
Dockerfile  index.html  nginx-1.20.1.tar.gz 

$ vim Dockerfile
FROM harbor.maple.com/oss/centos-base:v7.9.2009
MAINTAINER liangsircc@gmail.com
ADD nginx-1.20.1.tar.gz /usr/local/src
RUN yum install -y make vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop \
    && cd /usr/local/src/nginx-1.20.1 \
    && ./configure --prefix=/usr/local/nginx --with-http_sub_module \
    && make \
    && make install
COPY index.html /usr/local/nginx/html/index.html
RUN useradd -s /sbin/nologin nginx \
    && ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx
CMD ["nginx","-g","daemon off;"]
$ docker cp 6b8e2d2a5f19:/usr/local/nginx/conf/nginx.conf .
$ ls
Dockerfile  index.html  nginx-1.20.1.tar.gz  nginx.conf

6.2 modifying configuration files

$ vim nginx.conf
user  maple maple;
http {
    up_stream myapp1 {
        server 10.0.0.51:8080;
        server 10.0.0.52:8080;
    }
    server {
         location / {
            root   html;
            index  index.html index.htm;
        }
        location /myapp1 {
            proxy_pass http://myapp1;
        }
    }
}

6.3 modify Dockerfile and add nginx configuration file

$ vim Dockerfile 
FROM harbor.maple.com/oss/centos-base:v7.9.2009
MAINTAINER liangsircc@gmail.com
ADD nginx-1.20.1.tar.gz /usr/local/src
RUN yum install -y make vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop \
    && cd /usr/local/src/nginx-1.20.1 \
    && ./configure --prefix=/usr/local/nginx --with-http_sub_module \
    && make \
    && make install
COPY index.html /usr/local/nginx/html/index.html
ADD nginx.conf /usr/local/nginx/conf/
RUN ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx
CMD ["nginx","-g","daemon off;"]

6.4 build run test

$ bash build-command.sh
$ docker run  -p 8888:80 -d  harbor.maple.com/oss/nginx:v1


You can see that the work process is started by ordinary users

7. Copy the image to another host to run nginx2

$ docker save harbor.maple.com/oss/nginx:v1 > nginx.tar
$ scp nginx.tar 10.0.0.52:/home/maple/

#Another node is loaded and running
$ docker load -i nginx.tar 
$ docker run  -p 8888:80 -d  harbor.maple.com/oss/nginx:v1

test

8. Configure haproxy image 1

8.1 prepare the configuration file first

$ cd /opt/dockerfile/web/haproxy
$ ls
build-command.sh  Dockerfile  haproxy-2.4.1.tar.gz  haproxy.cfg  run_haproxy.sh

8.2 preparing haproxy configuration files

$ cat haproxy.cfg 
global
        chroot /usr/local/haproxy
        stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
        uid 99
        gid 99
        daemon
        nbproc 1
        pidfile /usr/local/haproxy/run/haproxy.pid
        log 127.0.0.1 local3 info
        defaults
        option http-keep-alive
        option forwardfor
        mode http
        timeout connect 300000ms
        timeout client 300000ms
        timeout server 300000ms
listen stats
        mode http
        bind 0.0.0.0:9999
        stats enable
        log global
        stats uri /haproxy-status
        stats auth haadmin:123456
listen web_port
        bind 0.0.0.0:80
        mode http
        log global
        balance roundrobin
        server web1 10.0.0.51:8888 check inter 3000 fall 2 rise 5
        server web2 10.0.0.52:8888 check inter 3000 fall 2 rise 5

8.3 preparation run_haproxy.sh script

$ cat run_haproxy.sh 
#!/bin/bash

/usr/local/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg

tail -f /etc/hosts

$ chmod +x run_haproxy.sh

8.4 dockerfile file

$ cat Dockerfile 
FROM harbor.maple.com/oss/centos-base:v7.9.2009
ADD haproxy-2.4.1.tar.gz /usr/local/src/
ADD haproxy.cfg /etc/haproxy/
ADD run_haproxy.sh /usr/bin/
RUN  yum install -y yum install gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel net-tools vim iotop bc zip unzip zlib-devel lrzsz tree screen lsof tcpdump wget ntpdate \
        && cd /usr/local/src/haproxy-2.4.1 \
        && make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 \
           USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/usr/local/haproxy \
        && make install PREFIX=/usr/local/haproxy \
        && cp haproxy /usr/sbin/ \
        && mkdir /usr/local/haproxy/run \
        && mkdir /var/lib/haproxy
EXPOSE 80 9999
CMD ["/usr/bin/run_haproxy.sh"]

8.5 Build run test

$ docker run -d -p 80:80 -p 9999:9999 harbor.maple.com/oss/haproxy:v1

9. Configure haproxy image 2

$ docker save harbor.maple.com/oss/haproxy:v1 > haproxy.tar
$ scp haproxy.tar 10.0.0.52:/home/maple/
#Another host loads and starts the container
$ docker load -i haproxy.tar
$ docker run -d -p 80:80 -p 9999:9999 harbor.maple.com/oss/haproxy:v1  

10. Configure keepalived

Two ways

  • The host runs keepalived
  • When the container runs keepalived, you need to configure – network=host

10.1 host machine running keepalived

10.1.1 installation

$ sudo apt install -y keepalived

#create profile
$ cat /etc/keepalived/keepalived.conf 
global_defs {
   notification_email {
     liangsircc@gmail.com
   }
   notification_email_from 395539184@qq.com
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id ka1.maple.com
   vrrp_skip_check_adv_addr
  # vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}
vrrp_script check_haproxy {
        script "/etc/keepalived/check_haproxy.sh"
        interval 1
        weight -40
        fall 3
        rise 2
        timeout 2
}
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 66
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass admin
    }
    virtual_ipaddress {
        10.0.0.50 dev eth0 label eth0:1
    }
    unicast_src_ip 10.0.0.51
    unicast_peer {
       10.0.0.52
    }
    track_script {
        check_haproxy
    }
}

#Create detection script
$ sudo vim /etc/keepalived/check_haproxy.sh
#!/bin/bash
if ss -tln | grep -E "\<80\>" &> /dev/null ;then
        exit 0;
else 
        exit 1;
fi

#start-up
sudo systemctl start keepalived.service

10.1.2 another host

$ apt install -y keepalived
$ cat /etc/keepalived/keepalived.conf 
global_defs {
   notification_email {
     liangsircc@gmail.com
   }
   notification_email_from 395539184@qq.com
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id ka1.maple.com
   vrrp_skip_check_adv_addr
  # vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}
vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 66
    priority 70
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass admin
    }
    virtual_ipaddress {
        10.0.0.50 dev eth0 label eth0:1
    }
    unicast_src_ip 10.0.0.52
    unicast_peer {
       10.0.0.51
    }
}

#start-up
$ sudo systemctl start keepalived.service 

You don't need to modify haproxy,
Because the haproxy configuration listens to 0.0.0.0, which contains the vip address

Test stop haproxy container
docker stop 07e3d40467c0

Observe whether vip is switched to another host 10.0.0.52
Whether the website is accessed normally

10.2 container operation kept alive

10.2.1 prepare package and configuration file first host

$ sudo systemctl stop keepalived.service #Stop the keepalived of the host first
$ cd /opt/dockerfile/web/keepalived
$ sudo cp /etc/keepalived/* .

# Build command
$ cat build-command.sh
#!/bin/bash
docker build -t harbor.maple.com/oss/keepalived:v1 .

#Detection script
$ cat check_haproxy.sh 
#!/bin/bash
if ss -tln | grep -E "\<80\>" &> /dev/null ;then
        exit 0;
else 
        exit 1;
fi

$ ls
build-command.sh  check_haproxy.sh  Dockerfile  keepalived.conf

10.2.2 building dockerfile

$ cat Dockerfile 
FROM harbor.maple.com/oss/centos-base:v7.9.2009
RUN yum install -y keepalived
ADD check_haproxy.sh /etc/keepalived/
ADD keepalived.conf /etc/keepalived/
CMD keepalived -f /etc/keepalived/keepalived.conf -l -n -D --vrrp

10.2.3 build and start the container

$ bash build-command.sh
# -- privileged needs to be added to enable the container to have permission to operate the host
# You need -- network=host to share the same network card between the container and the host
$ docker run -d --privileged --network=host  harbor.maple.com/oss/keepalived:v1 


# VIP 50 has been configured.
$ hostname -I
10.0.0.51 10.0.0.50 172.22.16.1 172.18.0.1 172.17.0.1 

10.2.4 create ka2 new directory, modify configuration and build image

10.2.4.1 preparation of configuration file

$ cd /opt/dockerfile/web/keepalived-backup
$ ls
build-command.sh  Dockerfile  keepalived.conf

10.2.4.2 Dockerfile

$ cat Dockerfile 
FROM harbor.maple.com/oss/centos-base:v7.9.2009
RUN yum install -y keepalived
ADD keepalived.conf /etc/keepalived/
CMD keepalived -f /etc/keepalived/keepalived.conf -l -n -D --vrrp

10.2.4.3 modify keepalived Conf configuration file

$ cat keepalived.conf 
global_defs {
   notification_email {
     liangsircc@gmail.com
   }
   notification_email_from 395539184@qq.com
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id ka1.maple.com
   vrrp_skip_check_adv_addr
  # vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}
vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 66
    priority 70
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass admin
    }
    virtual_ipaddress {
        10.0.0.50 dev eth0 label eth0:1
    }
    unicast_src_ip 10.0.0.52
    unicast_peer {
       10.0.0.51
    }
}

10.2.4.4 export to another host

$ docker save harbor.maple.com/oss/keepalived-backup:v1 > keepalived-backup.tar
$ scp keepalived-backup.tar 10.0.0.52:/home/maple/

10.2.4.5 load and start

$ docker load -i keepalived-backup.tar 
$ docker run -d --privileged --network=host  harbor.maple.com/oss/keepalived-backup:v1 

Test 10.0.0.51 the master node stops the haproxy container, vip automatically switches to 10.0.0.52 node, and the website is accessed normally.

Keywords: Docker Container keepalived dockerfile haproxy

Added by johnnyblaze9 on Mon, 17 Jan 2022 13:12:01 +0200