Docker镜像
概念
镜像:是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
UnionFS(联合文件系统):是一种分层、轻量级且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
Docker镜像加载原理:
Docker镜像由一层层的文件系统组成。
最底层是bootfs(boot file system),与Linux/Unix系统一样,包含boot加载器和内核。
rootfs(root file system)在bootfs智商,包含Linux系统中的标准目录和文件,就是各种不同的操作系统发行部,如Ubuntu,CentOS。
Docker分层结构的优势:
共享资源。多个镜像都从相同的base镜像构建而来,宿主机只需在磁盘上保存一份base镜像,同时内存中只需加载一份base镜像,就可以为所有容器服务。而且镜像的每一层都可以被共享。
特点:
Docker镜像都是可读的。当容器启动时,一个新的可写层被加载到镜像的顶部,这一层被称为“容器层”,容器层下的都叫“镜像层”。
Docker镜像commit操作补充
docker commit提交容器副本使之成为一个新的镜像
$ docker commit -m="提交的描述信息" -a="作者" id image:tag #容器ID,目标镜像名,标签名
案例演示
1. 从Hub上下载tomcat镜像到本地并成功运行
$ docker run -it -p 8080:8080 tomcat #指定端口
$ docker run -it -P tomcat #随机分配端口
2. 故意删除上一步镜像生产tomcat容器的文档
$ docker exec -it 13ddf4fffc8a /bin/bash
$ cd webapps
$ rm -rf docs
3. 当前的tomcat运行实例是一个没有文档内容的容器,以它为模板commit一个没有doc的tomcat新镜像
$ docker commit -m="del tomcat doc" -a="auth" 13ddf4fffc8a imagename:1.0
4. 启动新镜像和原镜像对比是否有docs
Docker数据卷
特点:
- 数据持久化,生命周期持续至没有容器使用它为止
- 容器间数据共享或重用
- 数据卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
容器内添加数据卷
直接命令添加
$ docker run -it -v /dataVolumeHost:/dataVolumeContainer centos #宿主机绝对路径目录,容器内目录,镜像名
- 查看数据卷是否挂载成功,通过
$ docker inspect
命令,Mounts部分查看挂载情况。 - 容器和宿主机之间数据共享,并且可读写,任意一方在文件夹中做出的更改都能实现共享
- 容器停止退出后,主机修改后数据同步
- 添加数据卷的同时设置容器权限,主机修改不受限制
$ docker run -it -v /dataVolumeHost:/dataVolumeContainer:ro centos #宿主机绝对路径目录,容器内目录,镜像名 ro-read only
DockerFile添加
- 根目录下新建文件夹并进入
- 在DockerFile中使用VOLUME指令给镜像添加一个或多个数据卷
- 创建DockerFile文件
# volume test
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "finished,---------success1"
CMD /bin/bash
- 依据DockerFile,build生成镜像
$ docker build -f ~/mydocker/DockerFile -t study/centos .
- run容器
$ docker run -it study/centos
1)Docker自动生成宿主机下的绝对目录,通过$ docker inspect
命令,Mounts部分查看宿主机地址。
2)对于Mac,Source这个地址在本机中并不存在,要查找共享文件需进入screen
$ screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty
3)进去之后默认是空白页面,按下Enter
$ cd /var/lib/docker/volumes/7cc099a019611c57312df7291efb55820cc7d46a8c929e280412a67784150633/_data
4)找到共享的文档,control+a+k退出screen,按y确认
可能出现的问题
Docker挂载主机目录Docker访问出现cannot open directory.:Permission denied
解决办法:在挂载目录后多加一个–privileged=true
数据卷容器
命名的容器挂载数据卷,其它容器通过挂载父容器实现数据共享,挂载数据卷的容器称为容器数据卷。
容器间传递共享(–volumes-from)
案例
之前通过DockerFile新建的镜像study/centos为模板并运行容器dc01/dc02/dc03,它们已经具有容器卷/dataVolumeContainer1与/dataVolumeContainer2。
- 启动父容器dc01,在dataVolumeContainer2新增内容
$ docker run -it --name dc01 study/centos
$ cd dataVolumeContainer2
$ touch dc01_add.txt
- dc02/dc03继承自dc01
$ docker run -it --name dc02 --volumes-from dc01 study/centos
$ docker run -it --name dc03 --volumes-from dc01 study/centos
- 回到dc01看到02/03各自添加的都可以共享
- 删除dc01,dc02修改后dc03可以访问
结论:容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止
DockerFile解析
概念
DockerFile:是用来构建Docker镜像的构建文件,由一系列命令和参数构成的脚本。
构建三步骤:
1)手动编写dockerfile文件
2)docker build创建自定义镜像
3)docker run
DockerFile构建过程解析
DockerFile内容基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按从上到下的顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层,并对镜像进行提交
Docker执行DockerFile的大致流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器进行修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行dockerfile中的下一条指令直到所有指令都执行完成
DockerFile体系结构
保留字指令 | 含义 |
---|---|
FROM | 基础镜像,当前新镜像是基于哪个镜像的 |
MAINTAINER | 镜像维护者的姓名和邮箱地址 |
RUN | 容器构建时需要的命令 |
EXPOSE | 当前容器对外暴露的端口号 |
WORKDIR | 指定在创建容器后,终端默认登陆的工作目录,一个落脚点 |
ENV | 用来构建镜像过程中设置环境变量 |
ADD | 将宿主机目录下的文件拷贝进镜像,ADD命令会自动处理URL和解压tar压缩包 |
COPY | 类似ADD,拷贝文件和目录到镜像中。 将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置 |
VOLUME | 容器数据卷,用于数据保存和持久化工作 |
CMD | 指定一个容器启动时要运行的命令 DockerFile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换 |
ENTRYPOINT | 指定一个容器启动时要运行的命令 ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及参数 |
ONBUILD | 当构建一个被继承的DockerFile时运行命令,父镜像在被子继承后父镜像的onbuild触发 |
案例
Base镜像scratch
Docker Hub中99%的镜像都是通过在base镜像中安装和配置需要的软件构建出来的
自定义镜像mycentos
- 编写DockerFile
FROM centos
MAINTAINER author<author@163.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "success----ok"
CMD /bin/bash
- 构建
$ docker build -f /mydocker/DockerFile -t mycentos:1.0 .
- 运行镜像文件
$ docker run -it mycentos:1.0
CMD/ENTRYPOINT镜像实例
都是指定一个容器启动时要运行的命令
CMD
DockerFile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换。
$ docker run -it -p 7777:8080 tomcat ls -l
相当于CMD ls -l /usr/local/tomcat
替换CMD ["catalina.sh", "run"]
执行,则上述命令并不会启动tomcat容器
ENTRYPOINT
docker run之后的参数会被当做参数传递给ENTRYPOINT,之后形成新的命令组合
案例:制作CMD版可以查询IP信息的容器
DockerFile2
FROM centos
RUN yum install -y curl
CMD ["curl","-s","http://ip.cn"]
创建镜像
$ docker build -f /mydocker/DockerFile2 -t myip:1.0 .
想要查询报头的容器,需要在后方添加完整命令
$ docker run myip:1.0 curl -s https://ip.cn -i
制作ENTRYPOINT版查询IP信息的容器
DockerFile3
FROM centos
RUN yum install -y curl
ENTRYPOINT ["curl","-s","http://ip.cn"]
创建镜像
$ docker build -f /mydocker/DockerFile3 -t myip:2.0 .
想要查询报头的容器,直接在后方添上命令即可
$ docker run myip:2.0 -i
案例自定义tomcat9
- 创建目录/mydockerfile/tomcat9/,新建c.txt文件
$ mkdir -p ~/mydockerfile/tomcat9/
$ cd ~/mydockerfile/tomcat9/
$ touch c.txt
- 将jdk和tomcat安装压缩包拷贝进上述目录
apache-tomcat-9.0.27.tar.gz
jdk-8u231-linux-x64.tar.gz - 在目录下创建Dockerfile文件
FROM centos
MAINTAINER auth<auth@google.com>
#把宿主机当前上下文的c.txt拷贝至容器/usr/local/路径下,并重命名
COPY c.txt /usr/local/cincontainer.txt
#把java和tomcat添加到容器中
ADD jdk-8u231-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.27.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_231
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.27
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.27
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.27/bin/startup.sh"]
# CMD ["/usr/local/apache-tomcat-9.0.27/bin/startup.sh","run"]
CMD /usr/local/apache-tomcat-9.0.27/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.27/bin/logs/catalina.out
- 构建
当未提供Dockerfile路径与文件名时,docker默认查找当前路径下的名为Dockerfile的文件运行
$ docker build -t mytomcat9 .
- 运行
后台运行,端口,容器名,容器卷x2,开启权限,镜像
$ docker run -d -p 9080:8080 --name myt9
-v /Users/xxx/mydockerfile/tomcat9/test:/usr/local/apache-tomcat-9.0.27/webapps/test
-v /Users/xxx/mydockerfile/tomcat9/tomcat9logs:/usr/local/apache-tomcat-9.0.27/logs
--privileged=true
mytomcat9
- 验证,访问http://localhost:9080/
- 结合前述的容器卷将测试的web服务test发布
1)在test文件夹下创建/WEB-INF/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_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>test</display-name>
</web-app>
2)创建a.jsp文件
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 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>Insert title here</title>
</head>
<body>
--------------welcome--------------
<%="i am in docker tomcat self"%>
<br>
<br>
<% System.out.println("============docker tomcat self");%)
</body>
</html>
3)docker restart
命令重启tomcat
4)访问http://localhost:9080/test/a.jsp,出现页面
Docker常用安装
MySQL安装
- Docker Hub上查找MySQL镜像
$ docker search mysql
- Docker Hub上拉取MySQL镜像到本地标签为5.6
$ docker pull mysql:5.6
- 使用mysql5.6镜像创建容器
$ docker run -p 12345:3306 #端口映射
--name mysql #服务器名
-v /Users/xxx/mydockerfile/mysql/conf:/etc/mysql/conf.d
-v /Users/xxx/mydockerfile/mysql/logs:/logs
-v /Users/xxx/mydockerfile/mysql/data:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=123456 #初始化root用户密码
-d mysql:5.6 #后台程序运行mysql 5.6
- 使用mysql镜像
$ docker exec -it 67123691b851 /bin/bash
$ mysql -uroot -p
- 数据库备份
$ docker exec 67123691b851 sh -c 'exec mysqldump --all-databases -uroot -p"123456"'> /Users/xxx/mydockerfile/mysql/all-databases.sql
参考资料
尚硅谷_Docker核心技术(基础篇)https://www.bilibili.com/video/av27122140