Docker之DockerFile
Nginx,tomcat,mysql 这些镜像都是哪里来的?官方能写,我们不能写吗?
我们要研究自己如何做一个镜像,而且我们写的微服务项目以及springboot打包上云部署,Docker就是最方便的
微服务打包成镜像,任何装了Docker的地方,都可以下载使用,极其的方便。
流程:开发应用=>DockerFile=>打包为镜像=>上传到仓库(私有仓库,公有仓库)=> 下载镜像 => 启动运行。
还可以方便移植!
什么是DockerFile
dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本
构建步骤:
- 编写DockerFile文件
- docker build 构建镜像
- docker run 运行镜像
- docker push 发布镜像
dockerfile文件我们刚才已经编写过了一次,这里我们继续使用 centos 来看!
地址:https:///_/centos
DockerFile 构建过程
基础知识
1、每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2、指令按照从上到下,顺序执行
3、# 表示注释
4、每条指令都会创建一个新的镜像层,并对镜像进行提交
流程
1、docker从基础镜像运行一个容器
2、执行一条指令并对容器做出修改
3、执行类似 docker commit 的操作提交一个新的镜像层
4、Docker再基于刚提交的镜像运行一个新容器
5、执行dockerfile中的下一条指令直到所有指令都执行完成!
说明
从应用软件的角度来看,DockerFile,docker镜像与docker容器分别代表软件的三个不同阶段。
- DockerFile 是软件的原材料 (代码)
- Docker 镜像则是软件的交付品 (.apk)
- Docker 容器则是软件的运行状态 (客户下载安装执行)
DockerFile 面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可!
DockerFile:需要定义一个DockerFile,DockerFile定义了进程需要的一切东西。DockerFile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当引用进行需要和系统服务和内核进程打交道,这时需要考虑如何设计 namespace的权限控制)等等。
Docker镜像:在DockerFile 定义了一个文件之后,Docker build 时会产生一个Docker镜像,当运行
Docker 镜像时,会真正开始提供服务;
Docker容器:容器是直接提供服务的。
DockerFile 指令
关键字
FROM # 基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER # 镜像维护者的姓名混合邮箱地址
RUN # 容器构建时需要运行的命令
EXPOSE # 当前容器对外保留出的端口
WORKDIR # 指定在创建容器后,终端默认登录的进来工作目录,一个落脚点
ENV # 用来在构建镜像过程中设置环境变量
ADD # 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY # 类似ADD,拷贝文件和目录到镜像中!
VOLUME # 容器数据卷,用于数据保存和持久化工作
CMD # 指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最 后一个生效!
ENTRYPOINT # 指定一个容器启动时要运行的命令!和CMD一样
ONBUILD # 当构建一个被继承的DockerFile时运行命令,父镜像在被子镜像继承后,父镜像的 ONBUILD被触发
实战测试
Docker Hub 中99% 的镜像都是通过在base镜像(Scratch)中安装和配置需要的软件构建出来的
自定义一个centos
编写DockerFile
目的:使我们自己的镜像具备如下:登陆后的默认路径、vim编辑器、查看网络配置ifconfifig支持
编写DockerFile文件
[root@rlj home]# vim mydocker-file-centos
[root@rlj home]# cat mydocker-file-centos
FROM centos
MAINTAINER r1895<1535045887@>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "------end------"
CMD /bin/bash
构建
docker build -f dockerfile地址 -t 新镜像名字:TAG .
[root@rlj home]# docker build -f mydocker-file-centos -t mycentos:0.1 .
...
Removing intermediate container 8946014ce86e
---> d577f2944be6
Successfully built d577f2944be6
Successfully tagged mycentos:0.1
运行
docker run -it 新镜像名字:TAG
[root@rlj home]# docker run -it mycentos:0.1
[root@3d0ad466b440 local]# pwd
/usr/local
[root@3d0ad466b440 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.7 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:07 txqueuelen 0 (Ethernet)
RX packets 6 bytes 516 (516.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@3d0ad466b440 local]# vim test
[root@3d0ad466b440 local]#
可以看到,我们自己的新镜像已经支持 vim/ifconfig的命令,扩展OK!
列出镜像地的变更历史
docker history 镜像名
[root@rlj home]# docker history d577f2944be6
IMAGE CREATED CREATED BY SIZE COMMENT
d577f2944be6 3 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin… 0B
d60fdcab17dc 3 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
ebc024ad17bb 3 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
4d7c57650fd2 3 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B
76a6a762527b 3 minutes ago /bin/sh -c yum -y install net-tools 29.4MB
3e93044d6c42 3 minutes ago /bin/sh -c yum -y install vim 68MB
f1df2a6ad33c 4 minutes ago /bin/sh -c #(nop) WORKDIR /usr/local 0B
f4424bb36439 4 minutes ago /bin/sh -c #(nop) ENV MYPATH=/usr/local 0B
33998fabd6f1 4 minutes ago /bin/sh -c #(nop) MAINTAINER r1895<15350458… 0B
300e315adb2f 8 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 8 months ago /bin/sh -c #(nop) LABEL … 0B
<missing> 8 months ago /bin/sh -c #(nop) ADD file:bd7a2aed6ede423b7… 209MB
CMD 和 ENTRYPOINT的区别
两个命令都是指定一个容器启动时要运行的命令
CMD:Dockerfifile 中可以有多个CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换!
ENTRYPOINT: docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合!
测试
CMD命令
# 构建dockerfile
[root@rlj home]# vim dockerfile-cmd-test
[root@rlj home]# cat dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
# build 镜像
[root@rlj home]# docker run 408
# 执行
[root@rlj home]# docker run 3a0
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# 4、如果我们希望用 -l 列表展示信息,我们就需要加上 -l参数
[root@rlj home]# docker run cmdtest -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
# 问题:我们可以看到可执行文件找不到的报错,executable file not found。
# 之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。
# 因此这里的 -l 替换了原来的 CMD,而不是添加在原来的 ls -a 后面。而 -l 根本不是命令,所 以自然找不到。
# 那么如果我们希望加入 -l 这参数,我们就必须重新完整的输入这个命令:
docker run cmdtest ls -al
ENTRYPOINT命令
[root@rlj home]# vim dockerfile-entrypoint-test
[root@rlj home]# cat dockerfile-entrypoint-test
FROM centos
ENTRYPOINT ["ls","-a"]
[root@rlj home]# docker build -f dockerfile-entrypoint-test -t entrypointtest .
Sending build context to Docker daemon 219.8MB
Step 1/2 : FROM centos
---> 300e315adb2f
Step 2/2 : ENTRYPOINT ["ls","-a"]
---> Running in 71023f489789
Removing intermediate container 71023f489789
---> 12ad0b38edce
Successfully built 12ad0b38edce
Successfully tagged entrypointtest:latest
[root@rlj home]# docker run 12a
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
[root@rlj home]# docker run entrypointtest -l
total 56
drwxr-xr-x 1 root root 4096 Aug 15 13:15 .
drwxr-xr-x 1 root root 4096 Aug 15 13:15 ..
-rwxr-xr-x 1 root root 0 Aug 15 13:15 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 340 Aug 15 13:15 dev
drwxr-xr-x 1 root root 4096 Aug 15 13:15 etc
drwxr-xr-x 2 root root 4096 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 4096 Dec 4 2020 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 2020 media
drwxr-xr-x 2 root root 4096 Nov 3 2020 mnt
drwxr-xr-x 2 root root 4096 Nov 3 2020 opt
dr-xr-xr-x 170 root root 0 Aug 15 13:15 proc
dr-xr-x--- 2 root root 4096 Dec 4 2020 root
drwxr-xr-x 11 root root 4096 Dec 4 2020 run
lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 2020 srv
dr-xr-xr-x 13 root root 0 Aug 15 13:15 sys
drwxrwxrwt 7 root root 4096 Dec 4 2020 tmp
drwxr-xr-x 12 root root 4096 Dec 4 2020 usr
drwxr-xr-x 20 root root 4096 Dec 4 2020 var
自定义镜像 tomcat
mkdir -p mbry/build/tomcat
- 在上述目录下 touch read.txt
- 将JDK和tomcat 安装的压缩包拷贝进上一步目录
- 在/mbry/build/tomcat 目录新建一个Dockerfile 文件
FROM centos
MAINTAINER mbry<1535045887@>
#把宿主机当前上下文的read.txt拷贝到容器/usr/local/路径下
COPY read.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-8u211-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.52.tar.gz /usr/local/
# 安装vim编译器
RUN yum -y install vim
# 设置工作访问时候的WORKDIR路径,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_211
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.52
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.52
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.52/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.52/bin/","run"]
CMD /usr/local/apache-tomcat-9.0.52/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.22/bin/logs/catalina.out
- 构建镜像
[root@rlj tomcat]# docker build -t diytomcat .
[root@rlj tomcat]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
diytomcat latest 194013b2866e 23 seconds ago 700MB
- 运行启动run
[root@rlj tomcat]# docker run -d -p 9090:8080 --name mydiytomcat -v /home/mbry/build/tomcat/test:/usr/local/apache-tomcat-9.0.52/wenapps/test -v /home/mbry/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.52/logs --privileged=true diytomcat
a0fd010dc4c0ab67e9fcc777941b1b16d8888ce69904b795d1ed9bd864ea0e31
[root@rlj tomcat]# docker exec -it a0fd010dc4c0 /bin/bash
[root@a0fd010dc4c0 local]# pwd
/usr/local
[root@a0fd010dc4c0 local]# ls
apache-tomcat-9.0.52 bin cincontainer.txt etc games include jdk1.8.0_211 lib lib64 libexec sbin share src
备注:Docker挂载主机目录Docker访问出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个–privileged=true参数即可
- 验证测试访问! curl localhost:9090
- 结合前面学习的容器卷将测试的web服务test发布
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>test</display-name>
</web-app>
a.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>hello,kuangshen</title>
</head>
<body>
-----------welcome------------
<%=" my docker tomcat,kuangshen666 "%>
<br>
<br>
<% System.out.println("-------my docker tomcat-------");%>
</body>
</html>
9.测试
[root@rlj test]# vim a.jsp
[root@rlj test]# curl localhost:9090/test/a.jsp
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Message</b> JSP file [/test/a.jsp] not found</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class=[root@rlj test]#
# 查看日志
cd tomcatlogs/
ll
发布镜像
DockerHub
注册dockerhub https:///signup,需要有一个账号
# 1、查看登录命令
[root@rlj test]# docker login --help
Usage: docker login [OPTIONS] [SERVER]
# 2、登录
[root@rlj test]# docker login -u mbry8040
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
# 3、将镜像发布出去
[root@rlj test]# docker push diytomcat
Using default tag: latest
The push refers to repository [/library/diytomcat]
9fd142b788c5: Preparing
be76907ff3a6: Preparing
53ca15d82747: Preparing
29ee7841ff2d: Preparing
2653d992f4ef: Preparing
# 拒绝:请求的资源访问被拒绝
denied: requested access to the resource is denied
# 问题: 本地镜像名无账号信息,解决 加tag即可
[root@rlj test]# docker tag 1940 mbry/diytomcat:1.0
# 再次push, ok
阿里云镜像服务
总结
镜像打包成为一个tar压缩包,可以发送压缩包给别人
docker save
docker load