一、Docker镜像
1、什么是镜像?
是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
2、镜像细节
- 分层下载:可以看一下
docker pull里面加载了很多,可以看出是分层的下载。
- 联合文件系统:UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
- 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
3、镜像加载原理
- bootfs(boot file system)主要包含bootloader和kernel,
bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。 - rootfs (root file system) ,在bootfs之上。只包含最基本的命令和工具及程序库。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
为什么docker要采用这种结构呢
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;
同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
4、docker镜像的commit操作实例
进入ubuntu发现不能执行vim命令,提示vim:command not found。也就是说这个命令没加载进来,需要加进来。
先更新包管理工具:apt-get update
然后安装我们需要的vim:apt-get -y install vim
创建目标镜像:docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
#docker ps能找到对应的目标镜像ID
[root@oliver001 ~]# docker commit -m="vim cmd add complete" -a="Oliver" 7091bf71621d myubuntu:1.1
sha256:0cc34e7219cdfd0942e2d54666ec17d446132fb693776d3f137d8da61cb39ef3
[root@oliver001 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myubuntu 1.1 0cc34e7219cd About a minute ago 177MB
tomcat latest fb5657adc892 5 months ago 680MB
bash latest 6a03c8e7e2be 6 months ago 12.9MB
ubuntu latest ba6acccedd29 7 months ago 72.8MB
这里可以看到创建的ubuntu有177MB,比之前大了很多。就像上面的图,先是一层base image,然后再加几层。
关掉之前的,打开最新的:
docker run -it 0cc34e7219cd(这是上面新创建的image id)
二、本地镜像发布到阿里云
1、镜像发布到阿里云的流程
2、本地镜像推送到阿里云
登录阿里云:阿里云-上云就上阿里云 (aliyun.com)
然后点击控制台,并登录自己的账号,点击容器镜像服务。
这样就进入了这个页面,点击个人服务。
选择创建命名空间,起一个名字。
选择镜像仓库,兵器创建镜像仓库。
选择本地仓库。
可以看到有很多指令:现在需要做的就是把本地的镜像推送到阿里云。
- 第一步:登录阿里云,回车后需要输入密码。
这里密码是123tzwsdzy。
docker login --username=阿里云账号名字 registry.cn-beijing.aliyuncs.com
- 第二步:加标签(这里写自己的,链接是不对的,主要是仓库名不对)
docker tag [ImageId] registry.cn-beijing.aliyuncs.com/oliver_docker/myubuntu:[镜像版本号]
#例子
docker tag 0cc34e7219cd registry.cn-beijing.aliyuncs.com/oliver_docker/myubuntu:1.3
- 推送到阿里云
docker push registry.cn-beijing.aliyuncs.com/oliver_docker/myubuntu:1.3
三、下载阿里云上的镜像
#先删除原来的镜像
docker rmi -f 镜像id
#拉取
docker pull registry.cn-beijing.aliyuncs.com/oliver_docker/myubuntu:[镜像版本号]
四、私有库的使用
- 下载docker registry,这是用来创建私有库的
docker pull registry
- 运行私有库Registry,相当于本地有个私有Docker hub
docker run -d -p 5000:5000 -v /zzyyuse/myregistry/:/tmp/registry --privileged=true registry
- 演示创建一个新的镜像,ubuntu安装ifconfig命令
docker run -it ubuntu /bin/bash
apt-get update
#或者使用 yum update
apt-get install net-tools
#或者使用 yum install net-tools/x86_64
- 创建新镜像
docker commit -m="ifconfig cmd complete" -a="Oliver" fe590c8a0c4b myubuntu:1.2
docker images
- curl验证私服库上有什么镜像
curl -XGET http://192.168.200.128:5000/v2/_catalog
- 将新镜像修改为符合规范的tag
#这里我们改成这个格式,方便查看,也可改成其他的
docker tag myubuntu:1.2 192.168.200.128:5000/myubuntu:1.2
#再使用docker images查看
- 修改配置文件使之支持http,因为默认是不支持的
#vim命令新增如下红色内容:
vim /etc/docker/daemon.json
#加镜像加速地址和自己的ip
{
"registry-mirrors": ["https://l1bjslsx.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.200.128:5000"]
}
#查看一下
cat /etc/docker/daomon.json
#重启docker保证生效
systemctl restart docker
- push推送到私服库
docker push 192.168.200.128:5000/myubuntu:1.2
- 再次使用curl验证私服库有什么镜像
curl -XGET http://192.168.200.128:5000/v2/_catalog
#现在变成这样了,有了myubuntu
{"repositories":["myubuntu"]}
- pull到本地运行
#先删除上面这个镜像
docker rmi -f 192.168.200.128:5000/myubuntu:1.2
#再拉取过来
docker pull 192.168.200.128:5000/myubuntu:1.2
五、容器数据卷
1、一点小问题
容器卷记得把--priviledge=true加上,这是因为docker挂载主机目录访问可能会出现cannot open directory:Permission deny的错误。
记得前面私有库敲了这么一行吗?docker run -d -p 5000:5000 -v /zzyyuse/myregistry/:/tmp/registry --privileged=true registry,里面的-v就是添加自定义的容器卷而后面的一串,:以前的是宿主机的路径,后面是容器内的路径。
2、作用
将运用与运行的环境打包镜像,run后形成容器实例运行 ,但是我们对数据的要求希望是持久化的。
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。
**这就是卷技术,把容器内的目录挂载到宿主机上。**有点类似于把自己家孩子让别人养,自己离世了,孩子也有别人可以帮忙照顾。
为了能保存数据在docker中我们使用卷。
3、运行带有容器数据卷存储功能的容器
指令是这样的。
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
例子就像上面写的。
4、特点
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接实时生效,爽
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
5、数据卷添加案例
(1)宿主vs容器之间映射添加容器卷
docker run -it -v /宿主机目录:/容器内目录 ubuntu /bin/bash
#例子
docker run -it --privileged=true -v /tmp/hostData:/tmp/docker_data --name ubun1 ubuntu /bin/bash
#先执行命令看一下,目录下什么都没有
[root@oliver001 ~]# docker run -it --privileged=true -v /tmp/hostData:/tmp/docker_data --name ubun1 ubuntu /bin/bash
root@c17ae5d25fea:/# pwd
/
root@c17ae5d25fea:/# cd /tmp/docker_data/
root@c17ae5d25fea:/tmp/docker_data# ls
root@c17ae5d25fea:/tmp/docker_data#
在容器中添加文件,可以在宿主机中看到也创建了这个文件;同理在主机中加入文件,容器中也显示这个文件。
root@c17ae5d25fea:/tmp/docker_data# touch dockerin.txt (容器中添加文件)
root@c17ae5d25fea:/tmp/docker_data# ls
dockerin.txt
root@c17ae5d25fea:/tmp/docker_data#
[root@oliver001 ~]# cd /tmp/hostData/ (宿主机也有这个文件了)
[root@oliver001 hostData]# ls
dockerin.txt
[root@oliver001 hostData]#
使用docker inspect 容器ID就可以看到详细信息。
Mounts: [
{
"Type": "bind",
"Source": "/tmp/hostData",
"Destination": "/tmp/docker_data",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
可以再看看docker容器stop掉了,主机修改后,docker容器重启后数据是否同步回来。
(2)默认情况下是互读互写的,也可以设置为只读
rw:就是可读可写;默认其实如下:
docker run -it -v /宿主机目录:/容器内目录:rw ubuntu /bin/bash
如果设置成只读不能写:
docker run -it -v /宿主机目录:/容器内目录:ro ubuntu /bin/bash
先exit这个容器,然后docker ps -a查看全部的(包括已经退出的),然后docker rm 相应的image id。
重新执行上面的指令即可。
这个时候再从容器添加文件就不行了:
root@b2367b3fc67b:/tmp/docker_data# touch a.txt
touch: cannot touch 'a.txt': Read-only file system
(3)容器卷的继承
容器1完成和宿主机的映射:
docker run -it --privileged=true -v /mydocker/u:/tmp/u --name u1 ubuntu
添加个文件:
[root@oliver001 ~]# docker run -it --privileged=true -v /mydocker/u:/tmp/u --name u1 ubuntu /bin/bash
root@d6760e5e5094:/# cd /tmp/u/
root@d6760e5e5094:/tmp/u# ls
root@d6760e5e5094:/tmp/u# touch a.txt
容器2继承容器1的容器规则:
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
#这里父类就是u1
docker run -it --privileged=true --volumes-from u1 --name u2 ubuntu
然后进入子类的容器查看也有父类创建的a.txt
root@88c32fe86d15:/# cd /tmp/u/
root@88c32fe86d15:/tmp/u# ls
a.txt
同时父类和子类都可以传递文件。
当把某一个主机关闭,对其他增加文件,等把它恢复了,发现其中也有其他添加的文件。
六、常规安装简介
1、步骤
搜索镜像-->拉取-->查看-->启动-->停止容器-->移除容器。
注意不知道命令的的最好去dockerhub上去查看一下,找到相应的软件,查看。
2、安装tomcat
docker hub上查找
docker search tomcat
拉取:
docker pull tomcat
查看:
docker images tomcat
创建容器实例:
docker run -d -p 8080:8080 --name tomcat1 tomcat
访问首页:localhost:8080,发现报错了。
[root@oliver001 ~]# docker exec -it 0354693f9eef /bin/bash
#先进入tomcat
#查看webapps里什么也没有,这才是tomcat不能访问的原因
#删除掉webapps
rm -f webapps
#把webapps.dist改名为webapps
mv webapps.dist webapps
这回就能进去了。
关掉docker stop tomcat1,再执行docker rm -f tomcat1,换成不需要修改文件的版本。执行下面两条指令即可。
docker pull billygoo/tomcat8-jdk8
docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
3、安装MySQL
查找
docker search mysql
拉取:
docker pull mysql:5.7
(1)简单版本
使用mysql镜像
docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
进入正在运行的容器:
docker exec -it a85cad0c276f /bin/bash
进入mysql:
mysql -uroot -p123456
但是插入中文可能会报错,是因为字符集的问题。
mysql> show variables like 'character%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
(2)实战版本
上面这种方式还是有点问题的。一般采用实战版本
docker pull mysql:5.7
新建mysql数据实例:
# 在/root目录下创建mysql目录用于存储mysql数据信息
mkdir ~/mysql
cd ~/mysql
创建窗口映射:
docker run -id \
-p 3307:3306 \
--name=c_mysql \
-v $PWD/conf:/etc/mysql/conf.d \
-v $PWD/logs:/logs \
-v $PWD/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7
参数说明:
- -p 3307:3306:将容器的 3306 端口映射到宿主机的 3307 端口。
- -v $PWD/conf:/etc/mysql/conf.d:将主机当前目录下的 conf/my.cnf 挂载到容器的 /etc/mysql/my.cnf。配置目录
- -v $PWD/logs:/logs:将主机当前目录下的 logs 目录挂载到容器的 /logs。日志目录
- -v $PWD/data:/var/lib/mysql :将主机当前目录下的data目录挂载到容器的 /var/lib/mysql 。数据目录
- **-e MYSQL_ROOT_PASSWORD=123456:**初始化 root 用户的密码
docker exec –it 容器ID /bin/bash
如果删除不了建议先docker ps -a查看全部的docker容器删除掉对应的。
新建my.cnf,通过容器卷同步给mysql容器实例
先cd到conf目录下
cd /zzyyuse/mysql/conf/
创建my.cnf文件
vim my.cnf
把这一段粘进去
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
再重新启动mysql容器,创建database和table,写个中文看看会不会有问题。
这样就能跑通了。
4、安装Redis
(1)简单版本
docker pull redis:6.0.8
docker run -d -p 6379:6379 redis:6.0.8
docker exec -it 容器ID /bin/bash
#执行redis-cli
但其实不是这么用的,需要加配置,还有要用到容器数据卷。
(2)实战版本
#先创建一个文件夹redis
mkdir -p /app/redis
#从以前安装的redis.conf处拷贝一个,放在/app/redis中
#执行下面的指令
docker run -p 6379:6379 --name myr3 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
#然后启动已经开启的容器,再按照简单版本redis-cli的指令即可