Dockerfile制作多应用的镜像(一、环境镜像)


文章目录

  • Dockerfile制作多应用的镜像(一、环境镜像)
  • 应用列表
  • 步骤
  • 一、制作环境镜像
  • Step1、下载需要的安装包
  • Step2、编写Dockerfile及启动脚本
  • Step3、docker build 构建镜像
  • Step4、docker run 启动容器
  • Step5、docker exec 进入容器进行验证
  • ==完成==


介绍基于centos7基础镜像,使用Dockerfile制作一个多应用的Docker镜像。

应用列表

  • CentOS 7.6
  • Mysql 5.7
  • JDK 1.8
  • Nginx 1.16.1
  • Python 3.6 anaconda
  • 其他项目应用

步骤

  1. 制作环境镜像:基于基础镜像centos7,安装mysql、anaconda、nginx、jdk
  2. 制作项目应用镜像:基于环境镜像,安装并启动项目应用的程序包

本文介绍的是第一步:制作环境镜像

一、制作环境镜像

主要步骤:
Step1、下载需要的安装包
Step2、编写Dockerfile及启动脚本
Step3、docker build 构建镜像
Step4、docker run 启动容器
Step5、docker exec 进入容器进行验证

Step1、下载需要的安装包

文件结构 /opt/dockermaker

[root@bg-244 dockermaker]# tree /opt/dockermaker
/opt/dockermaker
├── Anaconda3
│   ├── Anaconda3-5.2.0-Linux-x86_64.sh
│   ├── cachetools-4.0.0-py3-none-any.whl
│   ├── grpcio-1.27.2-cp36-cp36m-manylinux1_x86_64.whl
│   ├── msgpack-1.0.0-cp36-cp36m-manylinux1_x86_64.whl
│   ├── protobuf-3.11.3-cp36-cp36m-manylinux1_x86_64.whl
│   ├── pycryptodomex-3.9.7-cp36-cp36m-manylinux1_x86_64.whl
│   ├── redis-3.0.1-py2.py3-none-any.whl
│   └── redis_py_cluster-2.0.0-py2.py3-none-any.whl
├── bootstrap.sh
├── Dockerfile
├── java
│   └── jdk-8u221-linux-x64.tar.gz
└── mysql
   ├── mysql-community-client-5.7.29-1.el7.x86_64.rpm
   ├── mysql-community-common-5.7.29-1.el7.x86_64.rpm
   ├── mysql-community-libs-5.7.29-1.el7.x86_64.rpm
   ├── mysql-community-libs-compat-5.7.29-1.el7.x86_64.rpm
   ├── mysql-community-server-5.7.29-1.el7.x86_64.rpm
   └── mysql_init.sh

其中,mysql_init.sh是Dockerfile的RUN命令中执行的脚本,用于设置mysql数据库root临时密码为roottmp123
bootstrap.sh是Dockerfile的ENTRYPOINT命令中执行的脚本,基于当前镜像创建容器时会被执行。
为了高效地生成镜像,需要事先下载mysql、jdk、pip的安装包,使用本地安装。

Step2、编写Dockerfile及启动脚本

为了缩减镜像尺寸,应尽量注意:

  • 在一个RUN语句中执行多个命令,而不应该写多个RUN语句。
  • 清理无用文件:使用完的安装包,yum缓存等。

下面是代码及说明。

Dockerfile:

# 基础镜像
FROM centos:centos7
LABEL maintainer='jason9211' centos_version='7.6' mysql_version='5.7.29' jdk_version='1.8' nginx_version='1.16.1' python_version='3.6'

# 1、复制文件
WORKDIR /opt/Anaconda3
COPY  Anaconda3/Anaconda3-5.2.0-Linux-x86_64.sh    /opt/Anaconda3
COPY  Anaconda3/msgpack-1.0.0-cp36-cp36m-manylinux1_x86_64.whl    /opt/Anaconda3
COPY  Anaconda3/pycryptodomex-3.9.7-cp36-cp36m-manylinux1_x86_64.whl    /opt/Anaconda3
COPY  Anaconda3/grpcio-1.27.2-cp36-cp36m-manylinux1_x86_64.whl    /opt/Anaconda3
COPY  Anaconda3/protobuf-3.11.3-cp36-cp36m-manylinux1_x86_64.whl    /opt/Anaconda3
COPY  Anaconda3/cachetools-4.0.0-py3-none-any.whl    /opt/Anaconda3
COPY  Anaconda3/redis-3.0.1-py2.py3-none-any.whl    /opt/Anaconda3
COPY  Anaconda3/redis_py_cluster-2.0.0-py2.py3-none-any.whl    /opt/Anaconda3

WORKDIR /opt/mysql
COPY    bootstrap.sh    /opt/
COPY    mysql/mysql-community-client-5.7.29-1.el7.x86_64.rpm /opt/mysql
COPY    mysql/mysql-community-common-5.7.29-1.el7.x86_64.rpm /opt/mysql
COPY    mysql/mysql-community-libs-5.7.29-1.el7.x86_64.rpm /opt/mysql
COPY    mysql/mysql-community-libs-compat-5.7.29-1.el7.x86_64.rpm /opt/mysql
COPY    mysql/mysql-community-server-5.7.29-1.el7.x86_64.rpm /opt/mysql
COPY    mysql/mysql_init.sh    /opt/mysql

WORKDIR /opt/nginx/security

COPY java/jdk-8u221-linux-x64.tar.gz /opt

# 2、指定工作目录
WORKDIR /opt

# 3、安装
# install Anaconda3
RUN cd /opt/Anaconda3  \
    && yum -y install unzip zip --nogpgcheck  \
    && yum -y install bzip2 --nogpgcheck  \
    && echo "=====================================  Anaconda3 install start... "  \
    && bash Anaconda3-5.2.0-Linux-x86_64.sh -b -p /root/anaconda3 \
    && rm -f Anaconda3-5.2.0-Linux-x86_64.sh \
#    && echo "export PATH=/root/anaconda3/bin:$PATH" >> ~/.bashrc \
    && /root/anaconda3/bin/pip -V \
    && /root/anaconda3/bin/pip install msgpack-1.0.0-cp36-cp36m-manylinux1_x86_64.whl \
    && /root/anaconda3/bin/pip install pycryptodomex-3.9.7-cp36-cp36m-manylinux1_x86_64.whl \
    && /root/anaconda3/bin/pip install grpcio-1.27.2-cp36-cp36m-manylinux1_x86_64.whl \
    && /root/anaconda3/bin/pip install protobuf-3.11.3-cp36-cp36m-manylinux1_x86_64.whl \
    && /root/anaconda3/bin/pip install cachetools-4.0.0-py3-none-any.whl \
    && /root/anaconda3/bin/pip install redis-3.0.1-py2.py3-none-any.whl \
    && /root/anaconda3/bin/pip install redis_py_cluster-2.0.0-py2.py3-none-any.whl \
    && echo "=====================================  Anaconda3 install success "  \
    && echo "=====================================  mysql install start... "  \
    && cd /opt/mysql  \
    && yum install -y iproute --nogpgcheck  \
    && yum localinstall -y /opt/mysql/mysql-community-common-5.7.29-1.el7.x86_64.rpm --nogpgcheck  \
    && yum localinstall -y /opt/mysql/mysql-community-libs-5.7.29-1.el7.x86_64.rpm --nogpgcheck  \
    && yum localinstall -y /opt/mysql/mysql-community-libs-compat-5.7.29-1.el7.x86_64.rpm --nogpgcheck  \
    && yum localinstall -y /opt/mysql/mysql-community-client-5.7.29-1.el7.x86_64.rpm --nogpgcheck  \
    && yum localinstall -y /opt/mysql/mysql-community-server-5.7.29-1.el7.x86_64.rpm --nogpgcheck  \
    && rm -rf /opt/mysql/*.rpm  \
    && echo "=====================================  mysql install success "  \
    && echo "=====================================  mysql init start... "  \
    && mysqld --initialize --explicit_defaults_for_timestamp --user=mysql  \
    && chmod 777 /opt/bootstrap.sh \
    && chmod 777 /opt/mysql/mysql_init.sh \
    && bash /opt/mysql/mysql_init.sh \
    && echo "=====================================  mysql init success "  \
    && echo "=====================================  nginx install start... "  \
    && cd /opt/nginx  \
    && rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm  \
    && yum install -y nginx-1.16.1 --nogpgcheck  \
    && echo "daemon off;" >> /etc/nginx/nginx.conf \
    && echo "=====================================  nginx install success "  \
    && echo "=====================================  java install start... "  \
    && cd /opt \
    && tar -zxvf jdk-8u221-linux-x64.tar.gz \
    && rm -rf jdk-8u221-linux-x64.tar.gz \
    && echo 'export JAVA_HOME=/opt/jdk1.8.0_221' >> /etc/profile \
    && echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile \
    && echo 'export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar' >> /etc/profile \
    && source /etc/profile \
    && java -version \
    && echo "export JAVA_HOME=/opt/jdk1.8.0_221" >> ~/.bashrc \
    && echo "export PATH=/root/anaconda3/bin:$JAVA_HOME/bin:$PATH" >> ~/.bashrc  \
    && echo "export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar" >> ~/.bashrc  \
    && echo "=====================================  java install success "  \
    && rm -rf /var/cache/yum/* 

# 4、设置环境变量
ENV JAVA_HOME /opt/jdk1.8.0_221
ENV PATH /root/anaconda3/bin:/opt/jdk1.8.0_221/bin:$PATH
ENV CLASSPATH /opt/jdk1.8.0_221/lib/dt.jar:/opt/jdk1.8.0_221/lib/tools.jar

# 5、暴露的容器端口
EXPOSE 22 80 443 3306 8090 8091

# 6、容器运行时执行的脚本
ENTRYPOINT ["/opt/bootstrap.sh"]
CMD     ["/usr/sbin/init"]

mysql_init.sh:

#!/bin/bash
set -x
echo "#################################### mysql_init.sh start running..."
echo ""
INIT_ROOT_PASSWORD="roottmp123"
echo "############## set MYSQL root temp password : $INIT_ROOT_PASSWORD"

echo "############## start MYSQL ..."
mysqld --user=mysql & 
sleep 2
function start_mysql(){
for p in  {3..0};do
    PORT=$(ss -anlp|grep 3306|wc -l)
    if [ $PORT != 1 ]; then
        echo "[WARN] MYSQL not run, now start..."
        mysqld --user=mysql &
        sleep 2
    else
       echo "[WARN] MYSQL is running"
       break
    fi

    if [ $p = 0 ]; then
        echo >&2 '[ERROR] MYSQL start failed!'
        exit 1
    fi
done
}
start_mysql

echo "############## change MYSQL root temp password ..."
PASSWORD=$(awk '/password/{print $NF}' /var/log/mysqld.log)
echo "change root password..."
mysql --connect-expired-password -uroot -p"$PASSWORD" << EOF
alter user 'root'@'localhost' identified by '$INIT_ROOT_PASSWORD';
grant all on *.* to root@'%' identified by '$INIT_ROOT_PASSWORD';
EOF

echo "############## MYSQL shutdown... "
mysqladmin -uroot -p$INIT_ROOT_PASSWORD shutdown
echo "#################################### mysql_init.sh start finished "

bootstrap.sh:

#!/bin/bash
echo "#################################### bootstrap.sh start running..."
echo "############## start MYSQL ..."
mysqld --user=mysql & 

echo ""
echo "############# source /etc/profile"
source /etc/profile

echo ""
echo "############## show java version"
java -version

echo ""
echo "############## show pip version"
pip -V

echo ""
echo "############## nginx start by /usr/sbin/nginx. And bootstrap.sh finished..."
/usr/sbin/nginx

代码说明:
1)ENTRYPOINT脚本执行

COPY  bootstrap.sh    /opt/
RUN   chmod 777 /opt/bootstrap.sh
ENTRYPOINT ["/opt/bootstrap.sh"]
CMD     ["/usr/sbin/init"]

COPY语句复制过来的脚本,被Dockerfile限制了执行权限,需要chmod才能执行。
启动容器时,会执行ENTRYPOINT语句中指定的shell脚本/opt/bootstrap.sh
CMD在这里是启动容器时的默认参数。启动命令中如果设置了参数,将会覆盖CMD中的参数。

2)在docker中运行Nginx

在ENTRYPOINT脚本bootstrap.sh的最后一句是:

/usr/sbin/nginx

ENTRYPOINT脚本执行结束后,docker容器会自动停止。
所以为了避免这种情况,需要将Nginx设为daemon off;

RUN \
&& echo "daemon off;" >> /etc/nginx/nginx.conf \

或在Nginx启动时添加参数。

/usr/sbin/nginx -g 'daemon off;'

3)项目配置
建议在构建应用镜像时进行mysql库表初始化及Nginx配置。
在构建基础镜像时,尽量不要有项目痕迹。

4)使用mysql用户启动数据库

mysqld --initialize --explicit_defaults_for_timestamp --user=mysql
mysqld --user=mysql

5)Dockerfile中设置环境变量的方式

RUN \
&& echo "export PATH=/root/anaconda3/bin:$JAVA_HOME/bin:$PATH" >> ~/.bashrc  \

&& echo 'export JAVA_HOME=/opt/jdk1.8.0_221' >> /etc/profile \
&& source /etc/profile \
...

ENV JAVA_HOME /opt/jdk1.8.0_221

bootstrap.sh脚本中,也可以执行 source /etc/profile

6)清楚yum缓存

RUN \
    && rm -rf /var/cache/yum/*

Step3、docker build 构建镜像

构建镜像:

# 进入 Dockerfile 文件所在路径
cd /opt/dockermaker
# build --- 创建镜像的命令
# -t --- 指定target 名称
# centos-nmjpy:v1 --- 镜像名称:镜像tag
# . --- 执行当前路径下的 Dockerfile 文件
docker build -t centos-nmjpy:v1 .

查看镜像:

docker image ls
REPOSITORY      TAG       IMAGE ID       CREATED        SIZE
centos-nmjpy    v1        4bdd37c68d92   1 hours ago    6.14GB
centos          centos7   5e35e350aded   3 months ago   203MB

docker下会有两个镜像,一个是基础镜像centos:centos7,另一个就是刚刚构建的镜像。

查看镜像内部层级及大小:

docker history centos-nmjpy:v1

删除镜像:

# docker image rm <镜像名:tag 或 镜像ID>
docker image rm centos-nmjpy:v1
docker image rm 4bdd37c68d92

Step4、docker run 启动容器

启动容器:

docker run -v /tmp/:/tmp -itd --privileged --cap-add=SYS_ADMIN  \
    -p 40022:22 -p 40443:443 -p 40080:80 -p 43306:3306 \
    -p 48090:8090 -p 48091:8091 \
    --name=centos-nmjpy  \
    centos-nmjpy:v1 \
    /usr/sbin/init
  • -v /tmp/:/tmp :挂载宿主机的一个目录,冒号":"前面的目录是宿主机目录,后面的目录是容器内目录。
  • -it : 启动互动模式。
  • -d : 后台运行。
  • --privileged : 指定容器是否是特权容器。在docker容器运行时,让系统拥有真正的root权限。
  • --cap-add SYS_ADMIN : 添加系统的权限,不然系统很多功能都用不了的。
  • -p 43306:3306 :端口映射,格式:宿主机端口:容器端口
  • --name=centos-nmjpy :将容器命名为centos-nmjpy
  • centos-nmjpy:v1 :指定镜像,格式:镜像名称:镜像tag
  • /usr/sbin/init :初始容器里的CENTOS,用于启动dbus-daemon。

查看容器:

docker ps -a
  • -a :列出全部容器。若不加这个参数,只会列出正在运行的容器。
CONTAINER ID    IMAGE             COMMAND                  CREATED        STATUS       PORTS                                                                                                                                             NAMES
5f0d417764a6    centos-nmjpy:v1   "/opt/bootstrap.sh /…"   1 hours ago    1 hours ago  0.0.0.0:40022->22/tcp, 0.0.0.0:40080->80/tcp, 0.0.0.0:40443->443/tcp, 0.0.0.0:43306->3306/tcp, 0.0.0.0:48090->8090/tcp, 0.0.0.0:48091->8091/tcp   centos-nmjpy

停止容器:

# docker stop <容器名或容器ID>
docker stop centos-nmjpy
docker stop 5f0d417764a6

运行容器:

# docker start <容器名或容器ID>
docker start centos-nmjpy
docker start 5f0d417764a6

删除容器:

# docker rm <容器名或容器ID>
docker rm centos-nmjpy
docker rm 5f0d417764a6

Step5、docker exec 进入容器进行验证

进入容器:

docker exec -it centos-nmjpy bash

退出容器(不停止容器):
Ctrl+P+Q 同时按下

完成

至此,制作环境镜像就制作完成了,接下来就可以 制作项目应用镜像 了。