视频来源bilibili 尚硅谷周阳老师: 尚硅谷Docker
1、Docker 是什么?
比如我们在 Windows 上开发,发布到Linux上去,在 Windows 上的软件,移植到 Linux 上还需要在重新安装一次软件,配置环境,太麻烦了,因此 出现了 Docker ,Docker之所以发展如此迅速,也是因为它对此给出了一个标准化的解决方案-----系统平滑移植,容器虚拟化技术。
Docker 是通过将 源代码,配置环境,软件,软件版本…一些配置打包成镜像。将镜像在 Docker上运行,类似于 Vm 虚拟机的 iso 镜像文件。
总结起来一句话:解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
2、容器 VS 虚拟机
容器的发展过程:
从光盘到 卡台机,然后到 VM,然后到 DOcker
**虚拟机(virtual machine)**就是带环境安装的一种解决方案。可以在一套操作系统中安装另一套操作系统,iso 镜像文件 克隆了整套 CentOS 系统文件。
因此 虚拟机的缺点就是占用资源多,冗余步骤多,启动慢
容器 根据 虚拟机的缺点,Linux 容器发展了另外一种虚拟化技术,Linux 容器不是模拟一个完整的操作系统而是对进程进行隔离。有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一地运行。
容器和虚拟机对比:
*传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
*容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
2、Docker 能干吗
- 更快速的应用交付和部署
- 传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行。Docker化之后只需要交付少量容器镜像文件,在正式生产环境加载镜像并运行即可,应用安装配置在镜像里已经内置好,大大节省部署配置和测试验证时间。
- 更便捷的升级和扩缩容
- 随着微服务架构和Docker的发展,大量的应用会通过微服务方式架构,应用的开发构建将变成搭乐高积木一样,每个Docker容器将变成一块“积木”,应用的升级将变得非常容易。当现有的容器不足以支撑业务处理时,可通过镜像运行新的容器进行快速扩容,使应用系统的扩容从原先的天级变成分钟级甚至秒级。
- 更简单的系统运维
- 应用容器化运行后,生产环境运行的应用可与开发、测试环境的应用高度一致,容器会将应用程序相关的环境和状态完全封装起来,不会因为底层基础架构和操作系统的不一致性给应用带来影响,产生新的BUG。当出现程序异常时,也可以通过测试环境的相同容器进行快速定位和修复。
- 更高效的计算资源利用
- Docker是内核级虚拟化,其不像传统的虚拟化技术一样需要额外的 Hypervisor 支持,所以在一台物理机上可以运行很多个容器实例,可大大提升物理服务器的CPU和内存的利用率
docker官网:http://www.docker.com
Docker Hub官网: https://hub.docker.com/
前提条件
目前,CentOS 仅发行版本中的内核支持 Docker。Docker 运行在CentOS 7 (64-bit)上,
要求系统为64位、Linux系统内核版本为 3.8以上,这里选用Centos7.x查看自己的内核
uname命令用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。
Docker 的三大组成:
镜像(image)
- Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,**一个镜像可以创建很多容器。**docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。
容器(container)
- 容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台
- 可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
仓库(repository)
仓库(Repository)是集中存放镜像文件的场所。
类似于
Maven仓库,存放各种jar包的地方;
github仓库,存放各种git项目的地方;
Docker公司提供的官方registry被称为Docker Hub,存放各种镜像模板的地方。仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是 Docker Hub(https://hub.docker.com/),
存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云等其实和 Java 类似:
Book b1 = new Book(); Book b2 = new Book(); Book b3 = new Book();
Book 就类似于镜像,都是同一个类(镜像),new Book 类似于 容器,只不过Docker是 Redis r1 = Docker run 镜像
总结:
需要正确的理解仓库/镜像/容器这几个概念:
Docker 本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
镜像文件 : image 文件生成的容器实例,本身也是一个文件,称为镜像文件。
容器实例:一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例,也就是我们的容器
**仓库 :**就是放一堆镜像的地方,我们可以把镜像发布到仓库中,需要的时候再从仓库中拉下来就可以了。
工作原理:
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上, 然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。 容器,是一个运行时环境,就是我们前面说到的集装箱。
官网步骤: Install Docker Engine on CentOS | Docker Documentation
1、首先确定你的 CentOS版本为7 以上,内核版本为 3.8 以上
查看内核版本 uname -r 查看 CentOS版本 cat /etc/redhat-release
2、卸载之前的 旧版本
sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine
3、安装 gcc 环境
yum -y install gcc yum -y install gcc-c++
4、安装所需要的软件包
yum install -y yum-utils
5、建立远程仓库,注意:不要使用官网推荐的仓库,因为那是国外的,非常慢!!!!
推荐使用国内的镜像网站
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
6、更新 yum 软件包索引,非必须选项【主要是为了安装能快一些】
yum makecache fast
7、安装 Docker 引擎
yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
启动 Docker
Systemctl start docker
查看是否启动
ps -ef | grep docker
查看 docker 版本
docker version
使用 docker run hello world 测试:
run 进行的步骤:
卸载 Docker
systemctl stop docker yum remove docker-ce docker-ce-cli containerd.io rm -rf /var/lib/docker rm -rf /var/lib/containerd
官方:https://promotion.aliyun.com/ntms/act/kubernetes.html
登录之后,搜索 ’容器镜像服务“,复制加速器地址
配置 镜像加速器
sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://ey4yg4p8.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
为什么 Docker 比 虚拟机块?
(1)docker有着比虚拟机更少的抽象层
由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
(2) docker利用的是宿主机的内核,而不需要加载操作系统OS内核
当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。
启动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
命令 | 含义 | OPTIONS |
---|---|---|
docker images | 列出本地主机上的镜像 | -a :列出本地所有的镜像(含历史映像层) -q :只显示镜像ID。 |
docker search [OPTIONS] 镜像名字 | 搜索某个镜像 | –limit : N 列出N个镜像,默认25个 |
docker pull 镜像名字 | 拉取镜像,不指明版本号自动拉取最新版,相当于 latest | |
docker pull 镜像名字[:TAG] | 拉取镜像,指明具体的版本号 | |
docker system df | 查看镜像/容器/数据卷所占的空间 | |
docker rmi 镜像名字、镜像Id | 删除镜像 | -f : 强制删除 |
docker images
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签版本号
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小同一仓库源可以有多个 TAG版本,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像
docker search [OPTIONS] 镜像名字
显示前五条搜索记录:docker search --limit 5 redis
docker pull 镜像名字
docker rmi 镜像名字、镜像Id
可以单独使用镜像名字、镜像ID 或者镜像名字 + 版本号 进行删除
删除多个镜像:docker rmi -f 镜像名1:TAG 镜像名2:TAG
删除所有的镜像: docker rmi -f $(docker images -qa)
面试题:谈谈docker虚悬镜像是什么?
仓库名、标签都是的镜像,俗称虚悬镜像dangling image
详情后面讲
有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)
Docker 的内核是基于 Linux 内核的。因此需要在 Docker 上拉取一个 Ubuntu 或 CentOS 镜像:先拉 docker pull ubuntu
docker run [OPTIONS] IMAGE [COMMAND] [ARG…] : 新建+启动容器
OPTIONS说明(常用):有些是一个减号,有些是两个减号
–name=“容器新名字” 为容器指定一个名称;
-d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
也即启动交互式容器(前台有伪终端,等待交互);-P: 随机端口映射,大写P
-p: 指定端口映射,小写p
创建,启动 Ubuntu 容器 :
指定容器名字
、
docker ps [OPTIONS]
列出当前正在运行的容器-a :列出当前所有正在运行的容器+历史上运行过的
-l :显示最近创建的容器。
-n:显示最近n个创建的容器。
-q :静默模式,只显示容器编号。
退出容器
exit
: run进去容器,exit退出,容器停止
Ctrl + q + p
: run进去容器,ctrl+p+q退出,容器不停止
docker start 容器ID或者容器名
: 启动已经停止的容器
docker restart 容器ID或者容器名
: 重启容器
docker stop 容器ID或者容器名
: 停止容器
docker kill 容器ID或容器名
: 强制停止容器
docker rm 容器ID
: 删除已经停止的容器, rmi 是删除镜像,不加 i 是删除容器
docker rm -f $(docker ps -a -q)
: 一次删除多个实例
重要
一般将容器分为俩种类型,一种是启动交互式容器(前台命令行),另一种是启动守护式容器(后台服务器)
前台交互式启动 :
docker run -it redis:latest
后台守护式启动:
docker run -d redis:latest
一般像这种 redis,mysql…这种后台服务,建议采取后台守护式启动,Docker容器后台运行,就必须有一个前台进程.
docker logs 容器ID
: 查看容器日志
docker top 容器 ID
: 查看容器内运行的进程
docker inspect 容器ID
: 查看容器内部细节
docker exec -it 容器ID bashShell
: 重新进入容器注意它和 run 的区别,run 是重新启动、创建一个新的容器,而 exec 是重新进入之前创建好的容器
容器 ID 一样说明 是同一个容器。
docker attach 容器ID
: 重新进入容器attach 和 exec 的区别是什么?
docker cp 容器ID:容器内路径 目的主机路径
: 从容器中拷贝文件到主机上
导入导出容器
export 导出容器的内容留作为一个tar归档文件[对应import命令]
docker export 容器ID > 文件名.tar
import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]
cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
命令总结:
是什么?
是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是 image 镜像文件。
只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
分层的镜像 : 在我们下载镜像的时候其实也会发现, Docker 是一层一层下载的
UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。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等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M??
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
为什么 Docker 镜像要采用这种分层结构呢 ?
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
Docker镜像层都是只读的,容器层是可写的
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
实例一 — 提交一个自己的Docker镜像到本地
原始下载的 Ubuntu 镜像是不带有 vim 命令的。安装 vim 命令
apt-get update # 更新包管理命令 apt-get -y install vim # 安装 vim
使用 commit 命令,提交镜像到本地:
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
自定义的镜像,由于我们安装了 vim,大小会发生变化,使用该镜像创建的容器也带有 vim
总结
Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似Java继承于一个Base基础类,自己再按需扩展。
新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层
实例二 ---- 提交本地镜像到阿里云
第一步: 创建命名空间
第二步:创建镜像仓库
第三步:获取对应的脚本,执行响应的操作
推送镜像:
拉取镜像:
实例三 ---- 提交镜像到 私有库
1 官方Docker Hub地址:https://hub.docker.com/,中国大陆访问太慢了且准备被阿里云取代的趋势,不太主流。
2 Dockerhub、阿里云这样的公共镜像仓库可能不太方便,涉及机密的公司不可能提供镜像给公网,所以需要创建一个本地私人仓库供给团队使用,基于公司内部项目构建镜像。
Docker Registry是官方提供的工具,可以用于构建私有镜像仓库
第一步:下载 Registry 镜像
docker pull registry
第二步: 运行 Registry 镜像
docker run -d -p 5000:5000 -v /zzyyuse/myregistry/:/tmp/registry --privileged=true registry
第三步:创建一个新的镜像,并且安装 ifconfig
apt-get update apt-get install net-tools
第四步: 安装完后,一定要记得 commit,在容器外进行。
# 格式 docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名] # 输入的命令 docker commit -m="first commit ifconfig" -a="yzg" 7a4e2611f6e7 myubuntu2:1.1
第五步: curl 验证私服库上有什么镜像
curl -XGET http://192.168.200.132:5000/v2/_catalog
第六步:修改新镜像 myubuntu2 的 Tag 为符合私服规范的 Tag
# 格式 docker tag Repository:Tag Host:Port/Repository:Tag docker tag myubuntu2:1.1 192.168.200.132:5000/myubuntu:1.1
第七部:修改配置文件使之支持http
# 修改 该配置文件 vim /etc/docker/daemon.json { # 前面配置 阿里云镜像加速 的配置 "registry-mirrors": ["https://ey4yg4p8.mirror.aliyuncs.com"], # 新增的内容,注意IP地址修改成自己虚拟机的 "insecure-registries": ["192.168.200.132:5000"] }
如果不生效,建议重启 Docker
systemctl restart docker
,重启完 docker 记得 run 一下私服镜像第八步: push 镜像到私服库,并使用 curl 测试
第九步: pull 到本地并运行
回顾上一章,运行 registry 时 有一个 -v 参数
docker run -d -p 5000:5000
-v /zzyyuse/myregistry/:/tmp/registry --privileged=true
registry
容器数据卷 是什么?
一句话:有点类似我们Redis里面的rdb和aof文件,将docker容器内的数据保存进宿主机的磁盘中
容器数据卷能干什么?
对容器中的数据进行备份 + 持久化
特点:
1:数据卷可在容器之间共享或重用数据
2:卷中的更改可以直接实时生效,爽
3:数据卷中的更改不会包含在镜像的更新中
4:数据卷的生命周期一直持续到没有容器使用它为止
如何运行一个带有容器卷存储功能的容器 ?
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
宿主机绝对路径目录 : 就是 Centos
容器内目录 : 就是我们启动的 ubuntu
当宿主机或者容器内没有该指定的目录时,docker 会自动为我们创建目录
当我们在容器中创建文件时,宿主机也能立马同步过来。相反,也是一样的。当容器stop,主机修改时,容器启动也能同步
查看数据卷是否挂在成功
docker inspect 容器 ID
读写规则映射添加说明
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
rw: 表示容器内可读可写, read write 。默认不写就是可读可写
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
、ro : 表示 容器内只读,read only
卷的继承和共享
类似于 Java 中的继承。
怎么玩呢?
容器 1 完成和宿主机的映射,容器 2 继承容器 1 的宿主机的映射。
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
总体的步骤:
- 搜索镜像
- 拉取镜像
- 查看镜像
- 启动镜像
- 停止镜像
- 移除镜像
docker search tomcat # 搜索镜像,选择下载最多,好评最多的 docker pull tomcat # 拉取 docker run -d -p 8080:8080 tomcat # 运行 tomcat
-p :映射端口,主机端口: docker容器内部端口
- 主机端口,就是在外部访问的端口,会映射到 容器内部端口
-P : 随机分配端口
-d : 后台运行
当我们访问8080,却发现以下这种情况:
原因,在 tomcat 安装目录下的 webapps 是空的,需要将其删掉,将 webapps.dist 目录换成 webapps
因为下载的是最新版 10.0 的,需要修改, 8版本的tomcat是不需要修改文件的。
运行 8.0 版本的 tomcat :
docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
docker Hub : Docker Hub
搜索版本以及命令
启动 mysql :
docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234 -d mysql:5.7
启动 镜像 这些命令都在官网有说明
注意: LInux 本机上装了mysql,并启动了 mysql 服务,3306 端口就会被占用,Docker在启动 mysql 时 就会报错。
systemctl stop mysqld.service # 关闭 mysql 服务
启动完毕,使用 SQL_YOUNG 也可以连接
安装 MySQL 的坑:
- 当我们插入数据有中文时,docker上默认字符集编码隐患
查看 docker 的 mysql 编码集 :
SHOW VARIABLES LIKE 'character%'
不是 utf8 而是拉丁文。
- 还有一个问题,就是如果不小心把容器删除了,那么 mysql 中保存的数据也无法进行保存。
安装实战版的 MySQL
- 新建容器实例,并挂在数据卷,防止数据丢失
# 数据卷可以创建多个 docker run -d -p 3306:3306 --privileged=true -v /yzg/app/mysql/log:/var/log/mysql -v /yzg/app/mysql/data:/var/lib/mysql -v /yzg/app/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=1234 --name mysql mysql:5.7 # 注意密码是 1234
- 在宿主机的 /yzg/mysql/conf/ 下 新建 my.cnf 配置文件,并配置编码
[client] default_character_set= utf8 [mysqld] collation_server = utf8_general_ci character_set_server = utf8
- 配置完毕后,登录mysql
mysql -u root -p
- 查看编码集,并测试插入中文数据
SHOW VARIABLES LIKE 'character%'
中文编码错误已解决:
- 拉取 redis 镜像
docker pull redis:6.0.8
- 创建宿主机容器卷挂载目录: /yzg/app/redis , 并且拷贝一份原有的 redis.conf
cp /usr/local/redis/redis-6.2.1/redis.conf /yzg/app/redis/
- 修改配置文件 redis.conf
注释掉 bind ,并且将后台运行模式关掉,因为会和
docker run -d
起冲突如果想要外部客户端连接 redis, 把保护模式
protected-mode yes
改成 no
- 启动 redis
docker run -p 6379:6379 --name myr3 --privileged=true -v /yzg/app/redis/redis.conf:/etc/redis/redis.conf -v /yzg/app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
- 连接 redis
docker exec -it myr3 /bin/bash
测试 Redis 是否使用了 宿主机的配置文件,默认数据库 16 个,在宿主机上修改成 10 个。