目录

1、镜像(images)

1.1、Dockerfile:是制作镜像的文件

2、镜像结构原理

2.1、base 镜像

2.1.1、rootfs和bootfs

2.1.2、base 镜像提供的是最小安装的 Linux 发行版

2.2、镜像分层

2.2.1、为什么 Docker 镜像要采用这种分层结构呢?

2.3、容器可写层

3、制作镜像

3.1、制作镜像的过程

3.1.1、练习

3.2、Minimize the number of layers,减少层数

3.3、制作镜像的流程中可能会出现的问题

3.4、copy和add的区别

4、若是今后开发人员开发了新的代码,容器里的代码是否会自动更新?

5、为什么有些容器启动的时候需要使用 -it 有些不需要?

5.1、daemon off

6、使用容器跑一个go程序

7、harbor


1、镜像(images)

是打包好的软件,由程序代码、基础系统、依赖关系的软件包、系统库和工具组成 。

官方解释:

A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.

Docker容器映像是一个轻量级的、独立的、可执行的软件包,包含了运行应用程序所需的一切:代码、运行时、系统工具、系统库和设置。

[区分一下之前我们提到的centos镜像]

我们之前在linux安装centos提到的镜像是镜像站点的centos镜像,也叫映像文件。因为centos的官方是在国外,若是我们国内用户访问到国外的话,网速就特别慢。这个时候中国的企业就在中国搞一个镜像站点,把国外的东西复制一份放到国内来。那么国内的这个服务器就成为了国外服务器的镜像站点了。而我们现在要讲的这个镜像叫images,是docker容器里的镜像可以理解为是打包好的软件,是一个app的封装。

1.1、Dockerfile:是制作镜像的文件

参考文献:Docker Hub

点开里边的任意一个版本就能看到它的dockerfile

2、镜像结构原理

转载部分内容:第八篇:Docker镜像结构原理_Linux运维开发的技术博客_51CTO博客

2.1、base 镜像

base 镜像有两层含义:

  • 不依赖其他镜像,从 scratch 构建。

scratch:是最基础的docker镜像,相当于一个地基。

  • 其他镜像可以在此基础上进行扩展。

用别的镜像做基础镜像---》站在巨人的肩膀

base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等,以 CentOS 为例学习 base 镜像包含哪些内容。

这里拉了很多镜像,是因为这个镜像就是在一些基础镜像的基础上加一些镜像组成了python这个镜像

使用docker pull centos下载最新版本的Centos镜像也就207M左右,而我们平时下载一个原生的centos镜像都是4G,对于 Docker 初学者都会有这个疑问。

下载python镜像:

下面来了解下Linux 操作系统由内核空间和用户空间组成,如下图所示:

2.1.1、rootfs和bootfs

bootfs和rootfs里面就是一些程序和文件

bootfs:容器启动的时候需要的内容,是linux kernel 提供了bootfs

内核空间是 kernel,Linux 刚启动时会加载 bootfs 文件系统,之后 bootfs 会被卸载掉。用户空间的文件系统是 rootfs,包含我们熟悉的 /dev, /proc, /bin 等目录。对于 base 镜像来说,底层直接用 Host 的 kernel,自己只需要提供 rootfs 就行了。而对于一个精简的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了。相比其他 Linux 发行版,CentOS 的 rootfs 已经算臃肿的了,alpine 还不到 10MB。我们平时安装的 CentOS 除了 rootfs 还会选装很多软件、服务、图形桌面等,需要好几个 GB 就不足为奇了。

即我们的容器全部用宿主机的内核kernel,而容器提供的只是不同的系统文件。bootfs,容器启动的时候需要的内容;rootfs,容器内部的操作系统

2.1.2、base 镜像提供的是最小安装的 Linux 发行版

下面是 CentOS 镜像的 Dockerfile 的内容:

第二行 ADD 指令添加到镜像的 tar 包就是 CentOS 7 的 rootfs。在制作镜像时,这个 tar 包会自动解压到 / 目录下,生成 /dev, /porc, /bin 等目录。

2.2、镜像分层

Docker 支持通过扩展现有镜像,创建新的镜像。
实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如我们现在制作一个镜像

root@dockerserever:~# docker pull debian  # 下载一个debian的镜像

① 新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。
② 安装 emacs 编辑器。
③ 安装 apache2。
④ 容器启动时运行 bash。

构建过程如下图所示:

可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

2.2.1、为什么 Docker 镜像要采用这种分层结构呢?

最大的一个好处就是 - 共享资源。

比如:若是有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?
答:不会!因为修改会被限制在单个容器内。因为它有Copy-on-Write特性。

2.3、容器可写层

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

所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。
只有容器层是可写的,容器层下面的所有镜像层都是只读的。
下面我们深入讨论容器层的细节。
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a0.。在容器层中,用户看到的是一个叠加之后的文件系统。

1.添加文件
在容器中创建文件时,新文件被添加到容器层中。
2. 读取文件
在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,打开并读入内存。
3. 修改文件
在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。
4. 删除文件
在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。

只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。

3、制作镜像

[为什么要制作镜像?docker hub上不是有很多镜像吗?]

  • 不能满足我们的需求
  • 不够安全,有安全隐患

[谁去制作镜像?]

一般都是由开发人员去制作,也可以运维人员去制作或者权力比较大的工作人员,因为镜像里边涉及了公司里的机密代码等。

3.1、制作镜像的过程

第一步:新建一个空文件夹并pull一个python镜像

[root@centos7-docker ~]# mkdir /mydocker
[root@centos7-docker ~]# cd /mydocker/

第二步:新建Dockerfile

这里要注意,不要把注释放在代码的后边,不然待会run的时候运行不出来。

FROM python
# 我们在docker容器的工作目录。即进入docker容器的时候,所在的目录
WORKDIR /app # 复制当前目录下的所有内容到容器里边/app目录下
ADD . /app # 定义一个数据卷
VOLUME ["/data_flask"]# requirements.txt会写明我这个项目会需要一些什么python库;\
# 这条命令是告诉容器把requirements.txt里需要的库到pypi.python.org这个网站里边下载
# 这条命令是在制作镜像的时候要运行的,而不是在启动容器的时候运行的,这个要记住很容易混淆
RUN pip install  --trusted-host pypi.python.org -r requirements.txt# 暴露我们的端口号,即容器对外开放哪个端口
EXPOSE 80# 定义环境变量
ENV NAME World
ENV AUTHOR fan# 容器起来之后运行的第一个程序,这个是容器启动的时候运行,要和上边区分开来
CMD ["python", "app.py"]

另外的一些解释

第三步:新建requirements.txt文件

Flask
Redis

第四步:新建app.py文件

from flask import Flask
from redis import Redis,RedisError
import os
import socket# Connect to Redis   连接redis数据库
redis = Redis(host="redis", db=0,socket_connect_timeout=2, socket_timeout=2)app = Flask(__name__)# 访问这台机器的根"/"
@app.route("/")
def hello():try:# 若是有人访问,会往redis数据库里增加一个值visits = redis.incr("counter")except RedisError:# 这个visits是从redis数据库里获取的visits = "<i>cannot connect to REdis, counter disabled</i>"html = "<h3>Hello {name}!</h3>" \"<b>Hostname:</b>{hostname}<br/>" \"<b>Visits:</b> {visits}"# 返回这个主机名(socket.gethostname())和访问的次数(visits)return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(),visits=visits)if __name__ == "__main__":app.run(host='0.0.0.0', port=80)

第五步:生成镜像,需要一点时间,因为要下载很多东西

# -t,打个标记,等于给这个镜像取个名字
[root@centos7-docker mydocker]# docker build -t friendlyhello_1 .

生成镜像的时候,背后会自动生成临时的容器去执行Dockerfile里的命令,检测这个命令是否可以运行

[查看结果]

[root@centos7-docker ~]# docker images
REPOSITORY          TAG       IMAGE ID       CREATED         SIZE
friendlyhello_1     latest    82dda8055795   7 hours ago     935MB

第六步:运行容器

[root@centos7-docker docker]# docker run -d -p 5080:80 --name hello-1 friendlyhello_1
[root@centos7-docker docker]# docker ps
CONTAINER ID   IMAGE             COMMAND           CREATED         STATUS         PORTS                                   NAMES
c6dbd5383c7a   friendlyhello_1   "python app.py"   7 minutes ago   Up 7 minutes   0.0.0.0:5080->80/tcp, :::5080->80/tcp   hello-1
# 一定要做端口映射,不然到时候我们无法访问应用程序

[注意]: 若是我们使用"daocker ps"没有看到我们创建的容器在启动,那么就是我们之前编辑app.py  Dockerfile  requirements.txt,这三个文件有误。我们可以使用"docker logs + 容器名字"来看运行这个容器的时候出现了什么错误。

[root@centos7-docker mydocker]# docker logs hello-2* Serving Flask app 'app' (lazy loading)* Environment: productionWARNING: This is a development server. Do not use it in a production deployment.Use a production WSGI server instead.* Debug mode: off* Running on all addresses (0.0.0.0)WARNING: This is a development server. Do not use it in a production deployment.* Running on http://127.0.0.1:80* Running on http://172.17.0.3:80 (Press CTRL+C to quit)
192.168.29.1 - - [22/Apr/2022 13:19:18] "GET / HTTP/1.1" 200 -
192.168.29.1 - - [22/Apr/2022 13:19:18] "GET /favicon.ico HTTP/1.1" 404 -# 我这是执行成功了的情况

[结果查看]

因为redis服务没有安装,所以连接不到redis数据库,可以启动一个redis的容器,链接到现在这个容器

第七步:起一个redis容器

[root@centos7-docker docker]# docker run -d -p 6379:80 --name fan-redis-1 redis
a2b9a2ec08fa9efa1276efbefed4beaef25033bd56d8d888f3e61bfa46afad8b
[root@centos7-docker docker]# docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS          PORTS                                             NAMES
a2b9a2ec08fa   redis             "docker-entrypoint.s…"   4 seconds ago    Up 3 seconds    6379/tcp, 0.0.0.0:6379->80/tcp, :::6379->80/tcp   fan-redis-1
c6dbd5383c7a   friendlyhello_1   "python app.py"          22 minutes ago   Up 22 minutes   0.0.0.0:5080->80/tcp, :::5080->80/tcp             hello-1

起完之后,页面还是没有变化。因为我们虽然起了reids容器,但是不知道redis服务的IP地址是多少,所以连不过去。

[root@centos7-docker docker]# docker exec -it hello-1 /bin/bash
root@c6dbd5383c7a:/app# cat /etc/hosts
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2  c6dbd5383c7a  # 这里可以看到这个机器只知道自己的IP地址

因为这个镜像的命令太过于少了,所以没有vim和vi命令能够直接修改这个文件。但是我感觉直接修改这个文件,添加一条标明redis容器的IP地址的内容就可以访问到了。这里我们直接新建一个容器吧。

[root@centos7-docker mydocker]# docker run  -d --name hello-2 -p  5081:80 --link fan-redis-1:redis friendlyhello_1
ad7d079f9aa87da741303fc366311166b020617d4b5729916444881c75983647
[root@centos7-docker mydocker]# docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED             STATUS         PORTS                                             NAMES
ad7d079f9aa8   friendlyhello_1   "python app.py"          6 seconds ago       Up 6 seconds   0.0.0.0:5081->80/tcp, :::5081->80/tcp             hello-2
a2b9a2ec08fa   redis             "docker-entrypoint.s…"   About an hour ago   Up 6 minutes   6379/tcp, 0.0.0.0:6379->80/tcp, :::6379->80/tcp   fan-redis-1# 这里我们可以看到新建的hello-2有redis的IP地址
root@ad7d079f9aa8:/app# cat /etc/hosts
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2  redis a2b9a2ec08fa fan-redis-1
172.17.0.3  ad7d079f9aa8

[docker]七、docker镜像的制作(超详细)、docker镜像结构原理、镜像的分享——harbor相关推荐

  1. 了解MySQL(超详细的MySQL工作原理 体系结构)

    了解MySQL(超详细的MySQL工作原理 体系结构) 1.MySQL体系结构 2.MySQL内存结构 3.MySQL文件结构 4.innodb体系结构 一.了解MySQL前你需要知道的 引擎是什么: ...

  2. 超详细的MySQL工作原理 体系结构

    超详细的MySQL工作原理 体系结构 妖精的杂七杂八 2020-08-13 13:54:12 了解MySQL(超详细的MySQL工作原理 体系结构) 1.MySQL体系结构 2.MySQL内存结构 3 ...

  3. 超详细Docker部署SpringBoot+Vue项目(三更博客项目部署)

    文章目录 1.项目部署规划 2.前置工作 2.1修改后端配置文件ip 2.2修改前端Vue项目运行端口 2.3修改前端对应的服务器ip 2.4后端项目打包 2.4.1解决打包问题 2.4.2项目打包, ...

  4. 超详细Docker容器化自动部署(纯手打)

    微服务容器化自动部署 1. 传统手动部署: 首先基于源码打包生成jar包(或war包),将jar包(或war包)上传至虚 拟机并拷贝至JDK容器. 2. 通过Maven插件自动部署: 对于数量众多的微 ...

  5. 超详细docker入门级教程

    何夜息随笔录-docker入门级教程 文章目录 何夜息随笔录-docker入门级教程 什么是docker docker的组成 安装docker 卸载docker 阿里云镜像加速 docker的运行流程 ...

  6. Linux下Docker如何挂载启动nginx(超详细)

    前言:随着docker越来越火爆,很多东西都可以部署在docker上面:使用docker方便管理我们的应用:这篇博客将教会你如何使用docker部署nginx! 准备工作:部署好docker联网的li ...

  7. java+maven项目+tapd+jenkins+gitlab+sonarqube+docker实现自动化持续部署(超详细)

    文章目录 前言 相关介绍 一.准备 环境 二.安装docker 开放docker 2375端口 三.docker安装gitlab 修改gitlab.rb配置文件 进入容器重启配置 修改http的clo ...

  8. mysql主从配置duxi_手把手超详细Docker部署MongoDB集群

    Mongodb集群搭建 mongodb 集群搭建的方式有三种:主从备份(Master - Slave)模式,或者叫主从复制模式. 副本集(Replica Set)模式. 分片(Sharding)模式. ...

  9. 2023年CentOS镜像下载地址,包括CentOS官网、国内镜像下载,超详细教学,小白也能学会。

    目录 1.CentOS官网镜像下载 1.1进入CentOs官网镜像下载地址 1.2找到需要下载的版本 1.3选择isos镜像文件夹 1.4选择架构 1.5下载种子文件 2.阿里云开源镜像站下载 2.1 ...

  10. 超详细的Vue渲染原理讲解

    目录 一.Vue简介 1. MVVM.MVP和MVC 2. Vue的基本配置 二.Vue渲染原理 1. HTML与模板 2. Vue组件的完整渲染过程 (1). Vue自身的初始化阶段 (2). 组件 ...

最新文章

  1. Windows Phone 7、XNA的旋转的背景
  2. 对比3家平台,我总结了疫情数据可视化的8点经验
  3. HelloWorld 和相关设置
  4. js网页文件资源加载器
  5. Redis未授权访问漏洞记录(端口:6379)
  6. Vue基本操作及运行截图总结
  7. mysql case quchong_处理mysql的查询语句去重案例一则
  8. java jpanel对齐_java – 如何使用GridBagLayout在JPanel中对齐组件中心?
  9. 毕业设计不要再做 XX 管理系统了
  10. 移动流量转赠给好友_中国移动怎么才能转赠手机流量
  11. Java Poi 根据文字内容 插入 word 图片
  12. 中国人保为易集康健康科技承保产品责任险,为消费者保驾护航!
  13. 《管理学》第一章 管理与管理学
  14. 干货:如何打造一个直播平台
  15. 禁止APP录屏和截屏
  16. word2013插入excel对象报错_excel插入对象文件夹 Excel2013中插入对象文件的方法
  17. 学习表——受任于败军之际,奉命于危难之间(11.28-12.4)
  18. Java学习网站 [摘自互联网]
  19. Python学习笔记之网络爬虫
  20. 面对客户的“佩奇”需求,顶级外贸业务员该怎么做

热门文章

  1. 激活函数Relu 及 leakyRelu
  2. 车辆出险保险索赔技巧
  3. 怎么修改服务器图片存储路径,linux服务器存储图片路径
  4. vue3中使用swiper8 实现缩略图(thumbs的使用)
  5. 软件本地化测试比功能测试都有哪些方面需要注意?
  6. 易车买过车之后如何省钱
  7. 第十六届(2017)中国政府网站绩效评估结果发布 暨经验交流会在京顺利召开
  8. mysql技能特长怎么写_自我介绍性格技能兴趣特长.doc
  9. WinLicense 2.4.6.30 x86 / x64强大的技术和灵活性相结合
  10. 【UE4】【技巧】物体绕圆心转动(适用于转盘,旋转开关等)