Docker技术总结(基础篇02)

418 阅读12分钟

一、Docker镜像

1、什么是镜像?

是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。

2、镜像细节

  • 分层下载:可以看一下docker pull里面加载了很多,可以看出是分层的下载。

image.png

  • 联合文件系统: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等等。

img

为什么docker要采用这种结构呢

镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。

比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;

同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。

image.png

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、镜像发布到阿里云的流程

image.png

2、本地镜像推送到阿里云

登录阿里云:阿里云-上云就上阿里云 (aliyun.com)

然后点击控制台,并登录自己的账号,点击容器镜像服务。

image.png

这样就进入了这个页面,点击个人服务。

image.png

选择创建命名空间,起一个名字。

image.png

选择镜像仓库,兵器创建镜像仓库。

image.png

选择本地仓库。

image.png

可以看到有很多指令:现在需要做的就是把本地的镜像推送到阿里云。

  • 第一步:登录阿里云,回车后需要输入密码。

这里密码是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、特点

  1. 数据卷可在容器之间共享或重用数据
  2. 卷中的更改可以直接实时生效,爽
  3. 数据卷中的更改不会包含在镜像的更新中
  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,发现报错了。

image.png

[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的指令即可