【学习笔记】Docker(二)

Docker镜像加载原理

UnionFS(联合文件系统)

一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像(Docker下载镜像时一层层下载就是这个)

特征:一次性同时加载多个文件系统,但从外面看起来只能看见一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

Docker镜像加载原理

Docker的镜像实际上是由一层一层的文件系统组成,这种层级的文件系统即UnionFS

bootfs(boot file system):主要包括bootloads和kernel内核,bootloads主要是引导加载内核,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux系统是一样的,包括boot加载器和内核,当boot加载完成之后整个内核就在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs

rootfs(root file system):在bootfs上,包括的就是典型的Linux系统中的/dev、/proc、/bin、/etc等标准目录和文件,rootfs就是各种不同的操作系统发行版,比如Ubuntu、Centos等

所有的镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层:

例如基于Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层,如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层

Docker镜像都是只读的,当容器启动时,一个新的可写层被夹在到镜像的顶部!

这一层就是我们通常说的容器层,容器之下的都叫镜像层

然后可以将新的一层和原来的层一起打包成大的镜像进行发布

 

Commit镜像

docker commit 提交容器成为一个副本

docker commit -m=提交的描述信息 -a=作者 容器id 目标镜像名:[TAG]

容器数据卷

为了容器的持久化和同步操作-容器间实现数据共享

MySQL,容器删了数据就没了==需求:数据可以存储在本地

将容器内的目录挂载到虚拟机上

例:docker run -p 3306:3306 --name mysql --privileged=true

-v /mydata/mysql/log:/var/log/mysql

-v /mydata/mysql/data:/var/lib/mysql

-v /mydata/mysql/conf:/etc/mysql/conf.d

-e MYSQL_ROOT_PASSWORD=root  

-d mysql:8.0.26

-v /root/mysql/logs:/logs:将主机目录(/root/mysql)下的 logs 目录挂载到容器中的

/logs 日志目录

-v /root/mysql/data:/var/lib/mysql :将宿主机目录(/root/mysql)下的data目录挂载到容

器的 /var/lib/mysql 数据目录

docker inspect mysql(Mounts)查看挂载信息,数据挂载成功

进入容器内部docker exec -it mysql /bin/bashcd /var/lib/mysql查看容器内部数据

查看宿主数据目录,内容保持一致

Dockerfile

就是用来构建docker镜像的构建文件,命令脚本

--镜像是一层层的,脚本是一个个的命令,通过脚本可构建镜像

在Java8的环境下,将宿主/var/lib/docker/volumes/xxx/_data挂载到容器内部的/temp目录

Docker执行Dockerfile的大致流程如下:

(1)docker从基础镜像运行一个容器

(2)执行一条指令并对容器作出修改

(3)执行类似docker commit的操作提交一个新的镜像层

(4)docker再基于刚提交的镜像运行一个新容器

(5)执行dockerfile中的下一条指令直到所有指令都执行完成

DockerFile常用保留字指令

FROM -基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from

MAINTAINER -镜像维护者的姓名和邮箱地址

RUN -容器构建时需要运行的命令,有两种形式,一是后面加shell命令如RUN yum -y install vim,另一种是exec格式,如RUN [“./test.php”, “dev”, “offline”]

EXPOSE -当前容器对外暴露出的端口

WORKDIR -指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点

USER -指定该镜像以什么样的用户去执行,如果都不指定,默认是root

ENV用来在构建镜像过程中设置环境变量,这个环境变量可以在后续的其他指令中使用

ADD -将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包

COPY -类似ADD,拷贝文件和目录到镜像中。 将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置

VOLUME -容器数据卷,用于数据保存和持久化工作

CMD -指定容器启动后的要干的事情,格式跟RUN相似,和前面RUN命令的区别:CMD是在docker run 时运行,RUN是在 docker build时运行

docker学习(四):DockerFile微服务实战及docker端口映射_dockerfile指定端口映射_拒绝冗余的博客-CSDN博客

Docker网络

  1. 容器间的互联和通信以及端口映射
  2. 容器IP变动时候可以通过服务名直接网络通信而不受到影响

ens和lo接口:可以理解为宿主机的物理接口

在CentOS7的安装过程中如果有选择虚拟化的服务安装系统后,启动网卡时会发现有一个以太网桥连接的私网地址virbr0网卡(默认:192.168.122.1),作为虚拟机网桥的使用,为虚拟网卡提供NAT访问外网的功能。

启动docker后会产生一个名为docke0的虚拟网桥(桥接模式):

  1. Linux与Docker容器之间通过docker0是可以ping通的
  2. Docker容器与容器之间是可以相互ping通的

 Docker网络模式

  1. bridge:为每个容器分配设置IP,并将容器连接到docker0虚拟网桥,默认该模式
  2. host:容器不会虚拟出自己的网卡配置IP等,而是使用宿主机的IP和端口
  3. none容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接、IP等只有一个lo(即禁用网络功能),需要手动为容器添加网卡配置IP等
  4. container:新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口范围等,使用--network container:NAME或者容器ID指定

 

当docker启动MySQL,MySQL容器的连接到Bridge上的veth接口,形成veth-pair,默认的Bridge网络,网关默认是docker0,docker0的地址市172.17.0.1/24,则接入设备的IP以此类推:172.17.0.2/24

 

Docker网络,网络工程师还不赶紧收藏!_李白你好的博客-CSDN博客 

查看Bridge上接口的信息:bridge link

得到容器ID和veth bridge interface的关系

  1. 新建文件touch docker_eth_pair.sh
  2. vim docker_eth_pair.sh(具体内容见博客快速得到容器ID和veth bridge interface的关系_格洛米爱学习的博客-CSDN博客
  3. 赋予权限(chmod 777 docker_eth_pair.sh)
  4. 执行脚本./docker_eth_pair.sh
get_network_mode() {
    docker inspect --format='{{.HostConfig.NetworkMode}}' "$1"
}


created_by_kubelet() {
    [[ $(docker inspect --format='{{.Name}}' "$1") =~ ^/k8s_ ]]
}


for container_id in $(docker ps -q); do
    network_mode=$(get_network_mode "${container_id}")
    # skip the containers whose network_mode is 'host' or 'none',
    # but do NOT skip the container created by kubelet.
    if [[ "${network_mode}" == "host" || \
          $(! created_by_kubelet "${container_id}") && "${network_mode}" == "none" ]]; then
        echo "${container_id} => ${network_mode}"
        continue
    fi

    # if one container's network_mode is 'other container',
    # then get its root parent container's network_mode.
    while grep container <<< "${network_mode}" -q; do
        network_mode=$(get_network_mode "${network_mode/container:/}")
        # skip the containers whose network_mode is 'host' or 'none',
        # but do NOT skip the container created by kubelet.
        if [[ "${network_mode}" == "host" || \
              $(! created_by_kubelet "${container_id}") && "${network_mode}" == "none" ]]; then
            echo "${container_id} => ${network_mode}"
            continue 2
        fi
    done

    # get current container's 'container_id'.
    pid=$(docker inspect --format='{{.State.Pid}}' "${container_id}")

    # get the 'id' of veth device in the container.
    veth_id=$(nsenter -t "${pid}" -n ip link show eth0 |grep -oP '(?<=eth0@if)\d+(?=:)')

    # get the 'name' of veth device in the 'docker0' bridge (or other name),
    # which is the peer of veth device in the container.
    veth_name=$(ip link show |sed -nr "s/^${veth_id}: *([^ ]*)@if.*/\1/p")

    echo "${container_id} => ${veth_name}"
done

使用docker network inspect bridge查看特定网络的信息

 docker network create xx 创建网络(默认Bridge)

docker network rm xx删除指定网络

Docker容器内部的IP是会发生变化的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值