Fork me on GitHub

docker高级部分-Dockerfile,数据卷再认识

Docker高级部分笔记

初识Dockerfile

用来构建docker镜像的构建文件。构建docker镜像之前介绍了一种方式docker commit,另一种方式就是利用Dockerfile脚本文件生成。

解析Dockerfile文件

# 建议使用Dockerfile作为文件名
FROM centos

VOLUME ["volume1", "volume2"]

CMD "----END----"
CMD /bin/bash

# 这里的每个命令就是镜像的一层

执行Dockerfile文件

$ docker build -f Dockerfile -t nickel/my_centos .
# -f 指定dockerfile的路径
# -t target 指定目标,镜像的名称(不能以/开头)
# 最后的.不能忽略,表示输出的目录

启动刚才创建的容器

$ docker run -it --name my_iamges nickel/my_centos /bin/bash

这个卷一定在宿主机有相应的目录对应,具体可以通过命令查看

$ docker inspect my_iamges

其中有这样的信息

这就是挂载的数据卷的信息。

假设构建镜像时没有挂载镜像,可以使用-v手动挂载数据卷。

数据卷容器

$ docker run -it --name docker1 nickel/my_centos  # 创建并启动容器docker1
$ docker run -it --name docker2 --volumes-from docker1 nickel/my_centos # 创建并启动容器docker2,并且卷继承docker1

# 这样就能完成两个容器的数据卷的同步

同一个镜像产生的容器,数据卷共享就是这么简单,使用--volumes-from 就可以了,即使父容器停止了,依然不影响数据共享。这种共享实际是一种备份机制,而不仅仅是共享,docker1,docker2,docker3三个容器中的volume1里的数据是复制的,其中某一容器停止,不影响其他容器里的数据共享,就和容器和宿主机数据卷挂载一样。

现在有个问题,要是两个容器是从两个不同的镜像创建的会发生什么,或者能不能挂载?

多个mysql实现数据共享

# 只要多个mysql容器挂载相同的目录就可以了
$ docker run -d -p 3301:3306 --name mysql57_01 -v /Users/nickel/mysql/conf:/etc/mysql/conf.d -v /Users/nickel/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
$ docker run -d -p 3301:3306 --name mysql57_02 --volumes-from mysql57_01 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 就可以实现mysql57_01和mysql57_02使用相同的数据卷

结论:

容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用为止,可以理解为数据卷是独立容器存在的,容器可以不用运行,数据卷也可以独立存在,当没有任何容器使用数据卷(挂载),则该数据卷才会被销毁。但是一旦数据卷持久化宿主机,则宿主机上的数据不会随容器的销毁而销毁。

再识Dockerfile

构建步骤:

  1. 编写一个Dockefile文件
  2. docker build构建为一个镜像
  3. docker run 运行镜像
  4. docker push 发布镜像(docker hub等镜像仓库)

Dockerfile的指令

基础知识:

  1. 每个保留,关键字都是大写字母
  2. 指令是从上到下顺序执行
  3. #表示注释
  4. 每一个指令都会创建提交一个镜像层

Dockerfile是面向开发的,我们需要经常自己写Dockerfile文件。

开发三步骤:

开发:Dockerfile:构建文件,类似源代码

运维:Docker image:通过Dockerfile构建的镜像,是要交付的东西

部署:Docker 容器:就是镜像运行起来提供服务的

常用的指令

FROM         # 基础镜像,一切从这里开始构建
MAINTAINER   # 镜像是谁写的,提供姓名和邮箱
RUN          # 镜像构建的时候,需要运行的命令
ADD          # tomcat镜像,添加tocmat的压缩包,添加内容
WORKDIR      # 镜像的工作目录
VOLUME       # 挂载的目录
EXPOSE       # 暴露的端口配置
CMD          # 指定容器启动的时候要运行的命令,主要是替代
ENTRYPOINT   # 和CMD一样的,但CMD只有最后一个会生效,主要是追加命令
ONBUILD      # 当构建一个被继承的Dockerfile,这个时候就会运行ONBUILD指令
COPY         # 类似ADD命令,将文件复制到镜像中
EVN          # 构建的时候设置环境变量

练习自己写一个Dockerfile

docker中99%都是从scratch开始的。

创建自己的centos

# 1. 编写Dockefile文件
FROM centos
MAINTAINER nickel<cumtsgw@163.com>

ENV MYPATH /usr/local   # 定义变量MYPATH
WORKDIR $MYPATH         # 指定工作目录,创建容器,默认进入的目录 /usr/local

RUN yum install -y vim        # 安装vim
RUN yum install -y net-tools  # 安装网络工具,可以使用ifconfig命令

EXPOSE 80     # 暴露端口80

CMD echo $MYPATH
CMD echo "----end----"

CMD /bin/bash
# 2. 运行Dockerfile,构建镜像
$ docker build -f Dockerfile -t mycentos:0.1 .

# 3. 测试运行
$ docker run -it --name mycentos01 mycentos:0.1

# 4. 查看镜像的构建历史
$ docker history mycentos:0.1

查看镜像的构建历史命令;docker history 镜像ID

CMD和ENTRYPOINT的区别

# CMD 命令的Dockerfile
FROM centos

CMD ["ls", "-a"]

# 构建Dockerfile
$ docker build -f Dockerfile-cmd -t centos-cmd .

# 启动容器,结果是在容器根目录执行 ls -a
$ docker run centos-cmd

# 追加命令启动,结果会报错
$ docker run centos-cmd -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.
# 报错原因:-l 会替换CMD中定义的命令(ls -a),所以会报错
$ docker run centos-cmd ls -al  # 这样才不会报错,会用ls -al命令替换CMD中定义的["ls", "-a"]
# ENTRYPOINT 命令的Dockerfile
FROM centos

ENTRYPOINT ["ls", "-a"]

# 构建启动容器
$ docker build -f Dockerfile-entry -t centos-entry .
$ docker run centos-entry      # 结果会执行ls -a
$ docker run centos-entry -l   # 不会报错,结果会执行 ls -a -l

这就是CMD和ENTRYPOINT的区别,要仔细区分。

实战:tomcat镜像

  1. 准备镜像文件 tomat压缩包,jdk压缩包

  2. 编写Dockerfile文件

    FROM centos
    
    MAINTAINER nickel<cumtsgw@163.com>
    
    COPY readme.txt /usr/local/readme.txt
    
    ADD jdk-8u161-linux-x64.tar.gz /usr/local          # ADD命令会自动解压
    ADD apache-tomcat-9.0.31.tar.gz /usr/local
    
    RUN yum install -y vim         # 安装vim
    
    ENV MYPATH /usr/local
    
    WORKDIR $MYPATH     # 设置工作目录,也就是启动容器时默认进入的目录
     
    ENV JAVA_HOME /usr/local/jdk1.8.0_161       # 设置jdk相关的环境变量
    ENV CLASS_PATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    
    ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.31
    ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.31
    
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
    
    EXPOSE 8080    # 暴露端口
    
    CMD $CATALINA_HOME/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.31/logs/catalina.out    # 执行命令,使用&&连接要执行的多条命令,如果不是后台启动,会显示tail命令的内容
    
  3. 构建镜像

    $ docker build -t diy-tomcat .
    
  4. 运行容器

    $ docker run -d -p 9090:8080 --name nickel-tomcat -v /home/docker/diy-tomcat/test:/usr/local/apache-tomcat-9.0.31/webapps/test -v /home/docker/diy-tomcat/logs:/usr/local/apache-tomcat-9.0.31/logs diy-tomcat        # 挂载了几个目录
    

配置的tomcat修改conf/tomcat-users.xml以后还是不能管理tomcat,不知道什么原因,后面会继续寻找原因。

宿主机不能通过localhost:8080访问tomcat manager程序的原因

远程不能访问tomat manager的解决办法找到,不知道什么原因(具体原因可能和docker的网络有关,的确,容器启动的tomcat和宿主机是两台机器,不能用宿主机访问也能说得过去,但宿主机是通过localhost:8080访问的,tomcat是如何知道我是宿主机还是容器本身访问的?),使用容器启动的tomat,如果想要宿主机访问,需要开启远程访问,即使在宿主机上使用是localhost:8080的访问地址。
开启远程访问有两种方式:
tomcat开启远程管理Manager

  1. 方式一:
    打开/conf/Catalina/localhost/manager.xml,若没有文件,新建,添加以下内容(这种方法没测试过)
<Context privileged="true" antiResourceLocking="false"   
         docBase="${catalina.home}/webapps/manager">  
             <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="^.*$" />  
</Context> 
  1. 方式二:
    修改/webapps/manager/META-INF/context.xml,注释掉value里内容(测试过,可以实现)
<Context antiResourceLocking="false" privileged="true" >
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
</Context>
改为
<Context antiResourceLocking="false" privileged="true" >
    <!--
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
    -->
</Context>

/conf/tomcat-users.xml中添加角色就不说了。

  <role name="manager-gui"/>
  <role name="admin-gui"/>
  <user username="admin" password="admin" roles="manager-gui, admin-gui"/>

发布自己的镜像到docker hub

需要有docker hub的账号密码。

$ docker login -u cumtsgw
Login Succeeded.
$ docker tag 5168a3ed0675 cumtsgw/diy-tomcat:1.0  # 添加一个标签,把个人账号信息放上去cumtsgw
$ docker push cumtsgw/diy-tomcat:1.0    # 完成提交

不打标签,很可能会报错,因为直接提交diy-tomcat:1.0很可能是hub上有镜像了,会命名重复,前面加上个人账号。
但直接 docker push cumtsgw/diy-tomcat:1.0 会报错,提示没有这样的镜像,所以,可以先打一个标签,类似给镜像起一个别名,用这个别名提交,这样就保证能找到镜像,同时又保证镜像不冲突(账号是唯一的,所以镜像名冲突的可能性基本为零)。

发布镜像到阿里云仓库,参考官方文档

小结

posted @ 2020-09-06 10:16  Catalinas  阅读(549)  评论(0)    收藏  举报