Docker镜像,容器数据卷,安装Tomcat,MySQL和Redis
1. Docker镜像
1. 镜像
是一种轻量级的可执行的独立软件包,包含运行某个软件所需要的所有内容,将应用程序和配置依赖打包成一个可交付的运行环境(包括代码,运行时需要的库,环境变量以及配置文件等),打包好的运行环境就是image镜像文件
只有通过这个镜像文件才能生成Docker容器实例(类似于java中new出来一个实例)
UnionFS(联合文件系统):Union文件系统是一种分层的轻量级并且高性能的文件系统,支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(类似于java中的顶层父类Object),可以制各种具体的应用镜像
特点:一次性同时加载多个文件系统,从外面看起来只有一个文件系统,联合加载会将各层的文件系统叠加起来,最终的文件系统会包含所有底层的文件和目录
2. Docker镜像加载原理
docker镜像实际上是由一层层的文件系统组成,这种层级文件系统为UnionFS。bootfs(boot files system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时就会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与Linux系统是一样的,包含boot加载器和内核。当boot加载完之后整个内核就都在内存中,此时内存的使用权已由bootfs转交给内核,系统也会卸载bootfs。
rootfs(root file system):在bootf之上,包含的就是典型Linux系统中的/dev , /proc, /etc, /bin等标准目录和文件。rootfs就是各种不同的OS发行版,如Ubuntu,CentOS
Docker镜像层都是只读的,容器层是可写的。当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称之为’容器层’,容器层之下的都是’镜像层’。
3. Docker镜像commit操作案例
命令:
- docker commit 提交容器副本使之成为一个新的镜像
docker commit -m="提交的信息描述" -a="作者" 容器id 需要创建的目标镜像名:【标签名】
在docker上创建ubuntu容器之后,在该容器上安装vim:
- 从Hub上下载的Ubuntu镜像默认是不带有vim命令的
- 使用命令
apt-get update
和apt-get -y install vim
进行安装vim - 安装完成后,commit自己的新镜像:
docker commit -m=“add_vim_cmd” -a=“hz“ de0d0babc9bc /huzhen/MyUbuntu:3.8
总结:
Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似于java继承一个Base基础类,自己再按需扩展。
新镜像是从base镜像一层一层叠加生成的,每次安装一个软件,就在现有的镜像基础上扩展一层
4. 本地镜像发布到阿里云
- 创建仓库镜像:
- 选择控制台,进入容器镜像服务
- 选择个人实例
- 创建命名空间(类似于java中的包名)
- 仓库名称
- 进入管理界面获得脚本
- 将镜像推送到阿里云:
- 使用docker login登录时需要输入密码,也就是之前开通服务时设置的密码
本地也会生成该镜像的一个副本,以后可以使用docker pull registry.cn-hangzhou.aliyuncs.com/命名空间/镜像名:版本号
从阿里云上下载你之前发布到阿里云上的镜像
- 使用docker login登录时需要输入密码,也就是之前开通服务时设置的密码
5. Docker Registry
Docker Registry是官方提供的工具,可用于构建私有镜像仓库
-
下载Docker Registry镜像:
docker pull registry
-
运行私有库Registry,相当于本地有一个私有Docker hub:
docker run -d -p 8080:80 -v /hz/myregistry/:/tmp/registry --privileged=true registry
默认情况下,仓库被创建在容器的**/var/lib/registry**目录下,建议使用容器卷映射,方便宿主机联调
-
演示创建一个新的镜像,Ubuntu安装ifconfig命令:
docker run -it 镜像id /bin/bash
apt-get update
apt-get install net-tools
- ifconfig:查看容器内部的ip地址
docker commit -m="add_ifconfig" -a="hz" 容器id ubuntu:版本号
:反向生成一个带有ifconfig命令的ubuntu镜像,并且保存到仓库中
-
curl验证私服库上有什么镜像:
curl -XGET http://主机IP:端口号/v2/_catlog
-
将新镜像ubuntu:20.0修改为符合私服规范的tag:
- docker tag 镜像名:tag Host:Port/Repository:Tag
- 这里的Host为主机IP地址,即连接虚拟机的Ip地址,Repository:Tag为镜像名:版本号
docker tag hz/ubuntu:20.1 192.168.45.128:8080/hz/ubuntu:20.1
修改配置文件使之支持HTTP:docker默认是不允许HTTP方式推送镜像的,通过修改配置文件来关闭这个限制,修改完后需要重启docker
vim /ect/docker/daemon.json
{
"registry-mirrors": ["阿里云镜像源"],
"insecure-registries": ["主机ip:端口号"]
}
-
push推送到私服库:
docker push 192.168.45.128:8080/hz/ubuntu:20.1
-
curl验证私服库上的镜像
-
pull到本地运行:
docker pull 192.168.45.128:8080/hz/ubuntu:20.1
2. 容器数据卷
1. 容器卷中的参数
Docker挂载主机目录访问出现cannot open directory:Permission denied
解决:在挂载目录后面加上一个==–privileged=true==
如果是CentOS7安全模式比之前系统版本加强,不安全的会先被禁止,所以目录挂载的情况被默认为不安全的行为,使用上述命令解决挂载目录没有权限的问题,使用该参数,container内的root才有真正的root权限,否则container内的root只是外部的一个普通用户
docker run -d -p 8080:80 -v /hz/myregistry/:/tmp/registry --privileged=true registry
其中,-v /hz/myregistry/:/tmp/registry 冒号之前的为宿主机目录,冒号之后为容器目录,保证宿主机和容器之间的通信
docker容器数据卷作用
完成数据的持久化以及重要数据的backup,将容器内的数据备份+持久化到本地主机目录
2. 容器卷是什么
卷就是目录或者文件,存在于一个或者多个容器中,由docker挂载到容器中,但不属于联合文件系统,可以绕过Union File System提供一些用于持续存储或者共享数据的特性;
卷的设计目的就是数据的持久化,完全独立于容器的生命周期,因此Docker不会在容器删除时删除其挂载的数据卷
类似于Redis中的AOF和RDB文件,将docker容器内的数据保存到宿主机的磁盘中,运行一个带有容器卷存储功能的容器实例
3. 容器数据卷的作用
将运用与运行的环境打包成镜像,run后形成容器实例运行。Docker容器产生的数据如果不备份,那么当容器实例删除后,容器内的数据自然也就删除了,为了能保存数据在docker中使用容器卷
特点:
- 数据卷可在容器之间共享或者重用数据
- 卷中的更改可以直接实时生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用为止
4. 容器卷的案例
a. 宿主和容器之间映射添加容器卷
docker run -it --privileged=true -v 宿主机绝对路径:/容器内目录 镜像名
:可以实现容器卷和主机互相通信docker inspect 容器id
:查看数据卷是否挂载成功
- 容器和宿主机之间数据共享:当容器退出之后,宿主机修改的内容,在容器重新启动之后,容器中依旧会进行备份
b. 读写规则映射添加说明
- 读写默认规则:执行
docker run -it --privileged=true -v 宿主机绝对路径目录:/容器内目录:rw 镜像名:版本号
,默认的就是可读可写同步规则 - 只读:宿主机写的内容,可以同步到容器,但是要求容器内实例被限制,只能读取不能写,需要执行
docker run -it --name=容器名 --privileged=true -v 宿主机目录:/容器内目录:ro 镜像名:版本号 /bin/bash
c. 卷的继承和共享
-
容器1完成和宿主机的映射
docker run -it --name=ubuntu_add_ifconfig --privileged=true -v /home/huzhen/data:/tmp/myDockerData ubuntu:20.1 /bin/bash
-
容器2完成和容器1的卷规则(容器2继承容器1和主机的映射)
docker run -it --privileged=true --volumes-from ubuntu_add_ifconfig(父类容器名) --name=容器名 镜像id
如果父类容器1关闭之后,容器2依旧可以和宿主机进行交互通信,映射关系依旧存在。当容器1再次启动之后,容器1的内容以及和宿主机的映射关系也存在,类似于Redis中的一主多从
3. Docker上安装常用软件
1. 安装Tomcat
总体步骤:
- 搜索镜像
- 拉取镜像
- 查看镜像
- 启动镜像
- 停止容器
- 移除容器
-
docker hub上查找tomcat镜像
-
从docker hub上拉取镜像到本地:docker pull 镜像名:版本号(不指明默认下载最新版本的)
-
docker images tomcat查看是否下载成功
-
创建tomcat容器实例:
docker run -it -p 8888:8080 tomcat
-
访问Tomcat首页:访问不到首页的问题可能有
- 没有映射端口或者没有关闭防火墙
rm -r webapps
:删除webapps目录(默认访问的webapps文件夹内容是空的)mv webapps.dist webapps
:将webapps.dist目录替换成webapps
-
免修改版本(使用版本8.x的Tomcat已经够用了):
docker pull billygoo/tomcat-jdk8
docker run -d -p 8888:8080 --name Tomcat8 billygoo/tomcat8-jdk8
2. 安装MySQL(重要)
- 从docker hub中查找MySQL镜像
- 从docker hub上下载mysql镜像到本地,tag为5.7:docker pull mysql:5.7
- 使用MySQL5.7创建容器实例,可使用
ps -ef|grep mysql
查看Linux中是否已经下载过了MySQL,3306端口有没有被占用
docker run -p 3306:3306 --name MySQL5 -e MYSQL_ROOT_PASSWORD=hz1234 -d mysql:5.7
- 进入MySQL容器:
docker exec -it 容器id /bin/bash
- 也可以从本机windows上的客户端SQLyog进行连接数据库:主机地址即为虚拟机的IP地址,输入密码以及端口号即可连接(如果连接不上,关闭宿主机上的防火墙或者添加外部访问端口)
- 存在的问题:
- 插入中文数据会报错:docker上默认字符集编码为Latin
- 删除容器后,MySQL中的数据会全部被删除
解决以上问题,实战版的MySQL实例创建:
- 新建MySQL容器实例:-d开启守护者进程MySQL;-p指定端口,通过宿主机的3306端口即可访问到MYSQL容器;三个-v表示数据库的data,日志以及配置文件的容器卷挂载; -e设置mysql的登录密码;-name容器名
docker run -d -p 3306:3306 --privileged=true \
-v /home/huzhen/data/MySQL5/log:/var/log/mysql \
-v /home/huzhen/data/MySQL5/data:/var/lib/mysql \
-v /home/huzhen/data/MySQL5/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=xxxx --name MySQL5 mysql:5.7
- 在第一步中配置的宿主机的conf文件夹里新建my.cnf,通过容器卷同步给MYSQL容器实例,配置文件中的内容:
[client]
default_character_set=utf8
[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8
- 重新启动mysql容器实例再重新进入并查看字符编码
docker restart 容器名
docker exec -it 容器名 /bin/bash
mysql -u root -p
show variables like 'character%';
- 再新建数据库建表再插入中文测试
- 假如当前将容器实例删除,之前建的DB1数据库容器实例还能恢复,由于添加了容器卷,数据在宿主机上依旧存在备份
3. 安装Redis(重要)
- 与安装MySQL类似,也需要加上容器卷,并且加上命令
--privileged=true
- 在宿主机上新建目录/data/redis
- 将redis.conf配置文件拷贝到/data/redis目录下
- 在/data/redis目录下修改redis.conf配置文件
- 开启redis登录密码验证:requirepass 123
- 允许redis外地连接:注释掉 bind 127.0.0.1
- daemonize no:该参数和docker run -d参数会发生冲突,会导致容器一直启动失败
- 开启redis数据持久化:appendonly yes
- 使用Redis镜像创建容器:
docker run -p 6379:6379--name redis6 --privileged=true \
-v /home/huzhen/data/redis/redis.conf:/etc/redis/redis/conf \
-v /home/huzhen/data/redis/data:/data \
-d redis:6.2.6 redis-server /etc/redis/redis.conf
- 测试redis-cli连接上redis
- 证明docker启动使用手动指定的配置文件
- 修改配置文件中的相关参数,再次测试redis-cli连接上redis