目录
大家好,我是躺平哥,这是我的docker学习笔记基础篇,用来记录自己的学历历程,我感觉学习docker主要是多敲多练多看。我也是个小白,如果有写的不好的地方也请大家多多指点!
在公司开发过程中,开发需要清楚的告诉运维部署团队,用的全部配置文件+所有软件环境。不过,即便如此,仍然常常发生部署失败的状况。
于是——
docker诞生了
Docker的出现使得Docker得以打破过去「程序即应用」的观念。
透过镜像(images)将作业系统核心除外,运作应用程式所需要的系统环境,由下而上打包,达到应用程式跨平台间的无缝接轨运作。
大白话来讲:就是我把环境连带程序都给你一块打包起来了!
Docker是基于Go语言实现的云开源项目。
只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作。
一句话:
解决了运行环境和配置问题的软件容器, 方便做持续集成并有助于整体发布的容器虚拟化技术。
在了解docker之前我们先聊聊虚拟机,虚拟机也是一个伟大的发明!

传统虚拟机的缺点
- 资源占用多,因为它要模拟出一整套操作系统
- 冗余步骤多,虚拟机创建出一个操作系统往往要有很多步骤
- 启动慢,往往好几分钟。
由于前面虚拟机存在某些缺点,Linux发展出了另一种虚拟化技术:
Linux容器(Linux Containers,缩写为 LXC)
Linux 容器不是模拟一个完整的操作系统而是对进程进行隔离。
有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。
容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。
*容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
例如下图:

那话又说回来了——
●更轻量: 基于容器的虚拟化,仅包含业务运行所需的runtime环境,CentOS/Ubuntu基础镜像仅170M;宿主机可部署100~ 1000个容器
●更高效:无操作系统虚拟化开销
●计算:轻量,无极外开销
#存储:系统盘aufs/dmloverlayts; 数据盘volume
●网络:宿主机网络,NS隔离
.更敏捷、更灵活:
●分层的存储和包管理,devops理念
●支持多种网络配置
下面的图可以很清楚的看出docker各个组成之间的转换关系,以及对应命令:

Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以建很多容器。
它也相当于是一个root文件系统。比如官方镜像 centos:7 就包含了完整的一套 centos:7 最小系统的 root 文件系统。
相当于容器的“源代码”,docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。
下面我们从以下两个角度来介绍容器 :
1 从面向对象角度
Docker 利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台
2 从镜像容器角度
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
仓库(Repository)是集中存放镜像文件的场所。
最大的公开仓库是 DockerHub(Docker Hub)
tar与dockerfile以后会说
镜像文件
容器实例
仓库


(1)docker有着比虚拟机更少的抽象层:
(2)docker利用的是linux的内核,而不需要加载操作系统OS内核
- 启动docker : systemctl start docker
- 停止docker : systemctl stop docker
- 重启docker : systemctl restart docker
- 查看docker状态: systemctl status docker
- 开机启动 : systemctl enable docker
- 查看docker概要信息: docker info
- 查看docker 总体帮助文档: docker --help
- 查看docker命令帮助文档: docker 具体命令 --help
docker version //显示docker 的版本信息
docker info //显示docker 的系统信息 包括镜像和容器数量
docker 命令 -- help
REPOSITORY 仓库的镜像
TAG 镜像的标签,也就是镜像版本号,不写默认最新版
IMAGE ID 镜像的id
CREATE 镜像的创建时间
SIZE 镜像的大小
可选项
- -a --all 列出所有镜像
- -q --quiet 只列出镜像的id
可选项,通过搜索来过滤
[root@ecs-287241 ~]# docker search mysql --filter=stars=3000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 13384 [OK]
mariadb MariaDB Server is a high performing open sou… 5109 [OK]
[root@ecs-287241 ~]#
筛选starts大于3000的
下载镜像 docker pull 镜像名 [: tag版本]
- docker pull mysql
- 如果不写tag,默认就是latest
- 分层下载,这是docker images 的核心,联合文件信息
docker system df

docker rmi id
[root@ecs-287241 ~]# docker rmi -f feb5d9fea6a5
Untagged: hello-world:latest
Untagged: hello-world@sha256:18a657d0cc1c7d0678a3fbea8b7eb4918bba25968d3e1b0adebfa71caddbc346
Deleted: sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412
[root@ecs-287241 ~]# docker images
面试题:谈谈docker虚悬镜像是什么?
· 是什么
· 仓库名、标签都是
的镜像,俗称虚悬镜像dangling image · 长什么样

· 后续Dockerfile章节再介绍
说明:我们有了镜像才可以创建容器,linux,下载一个centos来学习
docker pull centos (centos小型的服务器)
docker run [可选参数] image
#参数说明(最常用参数)
--name="Name" 容器名字 tomcat1 tomcat2 用来区分容器
-d 后台方式运行
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
也即启动交互式容器(前台有伪终端,等待交互),就是等待你输入命令!
-it 使用交互方式运行,进入容器查看内容
为什么要写 -it?
不写-it你会发现是这样的
![]()
我们想要一个终端进行交互!输入命令,所以必须写!
![]()
后面往往还要写上/bin/bash: 是指此脚本使用/bin/bash来解释执行。/bin/bash:放在镜像名后的shell命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
#使用镜像centos:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。
docker run -it centos /bin/bash
或者
docker run -it centos bash 也可以!即使你没写/bin/bash 他也会默认在你后面带一个shell脚本

-p 指定容器的端口 -p 8080:8080
-p IP:主机端口:容器端口
-p 主机端口:容器端口 (常用)
-p 容器端口
-P: 随机端口映射,大写P
-p: 指定端口映射,小写p
一般我们用小p
如下图:
左边是宿主机暴露的端口,右边是docker访问redis暴露的端口

启动 并进入容器
[root@ecs-287241 ~]# docker run -it centos /bin/bash
查看容器内的centos,基础镜像都是不完善的
[root@882655ac322c /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
从容器中退到主机
exit
docker ps 命令
-a 当前正在运行,带出历史运行过的容器。
-l:显示最近创建的容器。
-n=? 最近创建的容器。
-q 静默模式,只显示容器的编号。
exit 直接容器停止并退出
ctrl +p +q 容器不停止退出
docker rm 容器id 删除指定的容器,不能删除正在运行的容器,如果要强制删除 rm -f
可以先docker stop 停止容器 再docker rm
docker rm -f $(docker ps -aq) 删除所有的容器
docker ps -a -qlxargs docker rm
docker satrt 容器id 启动容器
docker restart 容器id 重启容器
docker stop 容器id 停止当前正在运行的容器
docker kill 容器id 强制停止当前容器
- 命令 docker run -d 镜像名!
- docker run -d centos
- 问题docker ps,发现了 centos停止了
- docker run 之后一定要docker ps查看容器是否运行!
- 常见的坑,docker 容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止 。
- ngnix ,容器启动后,发现自己没有提供服务,就会立即停止,就是没有程序了
- Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器
如果在docker run后面追加-d=true或者-d,那么容器将会运行在后台模式。此时所有I/O数据只能通过网络资源或者共享卷组来进行交互。因为容器不再监听你执行docker run的这个终端命令行窗口。但你可以通过执行docker attach来重新附着到该容器的会话中。需要注意的是,容器运行在后台模式下,是不能使用--rm选项的。
在前台模式下(不指定-d参数即可),Docker会在容器中启动进程,同时将当前的命令行窗口附着到容器的标准输入、标准输出和标准错误中。也就是说容器中所有的输出都可以在当前窗口中看到。甚至它都可以虚拟出一个TTY窗口,来执行信号中断。
我们要在在容器中干活!
以redis容器为例,在里面干活

两个开发方式对比,想必你更能体会到容器的威力!

查看容器日志:docker logs 容器ID
docker logs -f -t --tail 容器,没有日志
显示日志
-tf 显示日志
--tail number 显示日志条数
查看容器内运行的进程
命令: docker top 容器id

命令:
查看容器内部细节
docker inspect 容器 id
我们通常容器都是使用后台放式运行的,需要进入容器,修改一些配置
方式一
#命令
docker exec -it 容器id bashShell
[root@ecs-287241 /]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6e5cf171dca0 centos "/bin/bash" 10 minutes ago Up 10 minutes serene_goodall [root@ecs-287241 /]# docker exec -it 6e5cf171dca0 /bin/bash [root@6e5cf171dca0 /]# ls bin etc lib lost+found mnt proc run srv tmp var dev home lib64 media opt root sbin sys usr [root@6e5cf171dca0 /]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 13:42 pts/0 00:00:00 /bin/bash root 15 0 0 13:54 pts/1 00:00:00 /bin/bash root 30 15 0 13:55 pts/1 00:00:00 ps -ef [root@6e5cf171dca0 /]#
docker attach 容器id
进入后会发现正在执行当前代码!
attach 直接进入容器启动命令的终端,不会启动新的进程 用exit退出,会导致容器的停止。
exec 是在容器中打开新的终端,并且可以启动新的进程 用exit退出,不会导致容器的停止。
docker exec 进入容器后开启一个新的终端,可以在里面操作(常用)
docker attach 进入容器正在执行的终端,不会启动新的进程
为了防止别人或者自己误删!所以要做备份
docker cp 容器id :容器内路径 目的主机路径
[root@ecs-287241 home]# docker cp 6e5cf171dca0:/home/test.java /home [root@ecs-287241 home]# ls one1 test1 test.java wei wei.java www [root@ecs-287241 home]#

拷贝是一个手动过程,未来我们使用 -v卷的技术,可以实现,自动同步
即容器内的home目录和主机内的home目录连通,打通
比拷贝docker cp 更加强大,这是拷贝整个容器!
· export 导出容器的内容留作为一个tar归档文件[对应import命令]
· docker export 容器ID > 文件名.tar
· import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]
· cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号

删除之后,利用import将abcd.tar变成一个镜像,然后在通过run运行成为一个容器。
下面我们来深入探究一下docker运行原理!
镜像
是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例!
以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载

一层一层的下载! 因此镜像是分层的。
UnionFS(联合文件系统):
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
Union文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
Docker镜像加载原理:
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
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等等。

说白了我们只要bootfs和rootfs!
平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M??

对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用宿主机的linux内核(Host的kernel),自己只需要提供 rootfs 就行了。
由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
就像这样:

那么话说回来了——
其实就是像乐高积木一样,想用哪块拿来组装就行了!
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;
同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
一句话来讲分层的意义:
加载简单,资源复用
· Docker镜像层都是只读的,容器层是可写的当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动——无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。

坑:容器卷记得加入
--privileged=true
why?
Docker挂载主机目录访问如果出现cannotopen directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true参数即可
如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为,
在SELinux里面挂载目录被禁止掉了额,如果要开启,我们一般使用--privileged=true命令,扩大容器的权限解决挂载目录没有权限的问题,也即使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。一个容器就相当于是一个小的linux内核。
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
· 一句话:有点类似我们Redis里面的rdb和aof文件
· 将docker容器内的数据保存进宿主机的磁盘中
· 运行一个带有容器卷存储功能的容器实例
· docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名

映射我们用“ :”,即冒号表示。
将运用与运行的环境打包镜像,run后形成容器实例运行 ,但是我们对数据的要求希望是久化的。
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没了。
为了能保存数据在docker中我们使用卷。
特点:
1:数据卷可在容器之间共享或重用数据。
2:卷中的更改可以直接实时生效,爽。
3:数据卷中的更改不会包含在镜像的更新中。
4:数据卷的生命周期一直持续到没有容器使用它为止。
docker:

host宿主机

docker inspect 容器ID
![]()

1 docker修改,主机同步获得
2 主机修改,docker同步获得
3 docker容器stop,主机修改,docker容器重启数据依旧同步。
因此即使是docker容器停止了也能够同步数据
只限制容器,没有限制主机

rw = read + write

· docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
· 默认同上案例,默认就是rw
· 只读
· 容器实例内部被限制,只能读取不能写

/容器目录:ro镜像名 就能完成功能,此时容器自己只能读取不能写
ro = read only
此时如果宿主机写入内容,可以同步给容器内,容器可以读取到。
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
操作一下:
容器


宿主机

docker run -it --privileged=true -v /mydocker/u:/tmp --name u1ubuntu



· docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
u3继承u1

u1stop掉了,u3和宿主机之间同步数据,u1start之后会同步数据吗?
会的!
1.容器上拷贝到linux上?cp
2.讲一个image启动成一个container容器?run
3.运行了容器怎么停止?kill/stop
4.怎么启动容器?start 怎么暂停?pause
5.logs:查看日志 inspect是干什么的?查看源数据
6.attach 进入已经启动的重端,而exec是启动一个新的终端
7.^p^q是以运行的方式退出
8.port 控制端口
9.ps可以看到当前所有的进程信息
10,top查看进程信息
port # 查看映射端口对应的容器内部源端口
pause # 暂停容器
ps # 猎户容器列表
pull # 从docker镜像源服务器拉取指定镜像或者库镜像
push # 推送指定镜像或者库镜像至docker源服务器
restart # 重启运行的容器
rm # 移除一个或多个容器
rmi # 移除一个或多个镜像 (无容器使用该镜像才可删除,否则需要删除相关容器才可继续或 -f 强制删除)
run # 创建一个新的容器并运行一个命令
save # 保存一个镜像为一个 tar 包【对应 load】
search # 在 docker hub 中搜索镜像
start # 启动容器
stop # 停止容器
tag # 给源中镜像打标签
top # 查看容器中运行的进程信息
unpause # 取消暂停容器
version # 查看 docker版本号
wait # 截取容器停止时的退出状态值
[root@ecs-287241 home]# docker run -d --name ngimx01 -p 3344:80 nginx 303bb4275798c811290a237bde71456194ed41fe82fdc9b03fb72df87edb6fbc [root@ecs-287241 home]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 303bb4275798 nginx "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 0.0.0.0:3344->80/tcp, :::3344->80/tcp ngimx01 [root@ecs-287241 home]# curl localhost:3344
If you see this page, the nginx web server is successfully installed and working. Further configuration is required.
For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.
Thank you for using nginx.
[root@ecs-287241 home]#root@303bb4275798:/# whereis ngnix
ngnix:地址
root@303bb4275798:/#
思考问题:我们每次改动nginx配置文件.都需要进入容器内部?
十分的麻烦,我要是可以在容器外部提供一个映射路径 ,达到在容器修改文件名,容器内部就可以自动修改? -v 数据卷
#官方的使用
docker run -it --rm tomcat:9.0
#我们之前的启动都是后台,停止了容器之后,容器还是可以查到
docker run -it --rm. 一般用来测试,用完就删除
感谢大家观看!