一、容器
1、什么是容器
容器是一种轻量级的虚拟化技术,它为应用程序提供了一种隔离的运行环境。在操作系统级别上实现,容器将应用程序及其所有依赖项(包括库、配置文件等)封装在一起,形成一个独立的标准单元。
每个容器都拥有自己的视图,即独立的进程空间、文件系统、网络接口和其他资源,这些资源都是从宿主机操作系统中虚拟化出来的,但不同于传统的虚拟机,它们共享同一个操作系统内核。
过去的部署方式
- 部署非常慢
- 成本非常高.
- 资源浪费.
- 难于迁移和扩展
- 可能会被限定硬件厂商
由于物理机的诸多问题,后来出现了虛拟机。
但是虚拟化也是有局限性的,每一个虚拟机都是一个完整的操作系统,要分配系统资源,虚拟机多道一定程度时,操作系统本身资源也就消耗殆尽,或者说必须扩容。
Linux部署形式
- vmware虚拟机+ centos (ISO镜像) =得到一个可以使用的linux系统。
- 如上的大前提,是你得有一个宿主机(你学习使用的电脑,macbook, windows笔记本)
容器的主要优势包括:
- 资源隔离:通过控制组(cgroups)限制和隔离CPU、内存、磁盘I/O等资源使用。
- 轻量化:相比于虚拟机,容器启动速度快,占用资源少,因为它们不需要为每个实例运行完整的操作系统。
- 可移植性:基于容器镜像构建的应用程序可以在任何支持容器技术的平台上运行,确保在不同环境下的行为一致性。
- 快速部署与扩展:容器使得开发、测试、生产和迁移过程变得更加灵活和高效,有利于DevOps实践。
常见的容器技术包括Docker以及其他遵循开放容器倡议(OCI)标准的工具,如rkt(Rocket)。容器编排工具如Kubernetes则允许在集群环境中有效地管理多个容器的生命周期和交互。
虚拟化技术
将计算的工作,放在云上去执行。
去阿里云购买RDS数据库服务,不需要自己搭建数据库,做数据库高可用等等。
我对数据的增删改查,用的全都是云上的数据库。
虚拟机工具巨头。
虚拟化技术是一种计算资源管理技术,它通过软件层(称为虚拟机监控器或VMM,如Hypervisor)将物理计算机的硬件资源抽象、模拟和隔离出来,使得单个物理主机可以同时运行多个独立且相互隔离的虚拟环境(称为虚拟机VMs)。每个虚拟机都拥有自己独立的操作系统、应用程序以及虚拟化的CPU、内存、磁盘、网络接口等资源。从虚拟机内部来看,它们就像在单独的物理机器上运行一样。
这种技术的主要优势包括:
- 资源利用率提升:通过整合多台服务器到更少的物理主机上,有效利用闲置的硬件资源。
- 灵活性与可扩展性:快速部署新的虚拟机以满足不断变化的工作负载需求,迁移虚拟机至其他物理主机而无需停机。
- 隔离与安全性:不同虚拟机之间互不影响,即使一个虚拟机发生故障或受到攻击,也不会波及到其他虚拟机或宿主机。
- 测试与开发环境简化:轻松创建和销毁虚拟环境,便于测试不同的操作系统配置和应用部署方案。
- 能耗与成本降低:减少数据中心所需的物理服务器数量,从而节约能源消耗和硬件采购、维护成本。
虚拟化技术不仅仅应用于服务器领域,还可以扩展到存储虚拟化(统一管理和分配存储资源)、网络虚拟化(逻辑上分割和管理网络资源)和桌面虚拟化(让用户远程访问虚拟桌面环境)等多个层面。
虚拟化工具
虚拟化工具涵盖了多个领域,以下是一些常见的服务器虚拟化、桌面虚拟化以及容器化平台工具:
服务器虚拟化工具:
-
VMware vSphere:一套企业级的服务器虚拟化平台,支持大规模的虚拟机管理和资源调度。
-
VMware ESXi:VMware的裸金属型Hypervisor,用于直接在硬件上运行虚拟机。
-
Microsoft Hyper-V:Windows Server操作系统的一部分,提供内置的虚拟化功能。
-
Oracle VM VirtualBox:开源且免费的虚拟机软件,适用于个人和小型商业用途,可以在不同类型的主机操作系统上运行。
-
Citrix Hypervisor (原名XenServer):基于Xen项目的开源技术构建的企业级虚拟化平台。
-
KVM (Kernel-based Virtual Machine):Linux内核中的全虚拟化解决方案,广泛应用于OpenStack等云平台。
桌面虚拟化工具:
-
VMware Horizon View:VMware的桌面虚拟化产品,让用户可以通过网络访问集中托管的虚拟桌面。
-
Microsoft Remote Desktop Services (RDS):允许用户通过网络远程访问Windows桌面和应用程序。
-
Citrix Virtual Apps and Desktops(以前的 XenApp 和 XenDesktop):提供应用程序和桌面虚拟化的解决方案。
容器化工具:
-
Docker:流行的开源容器平台,可以打包应用及其依赖为可移植的容器。
-
Kubernetes (K8s):Google开发的容器编排系统,用于自动化容器部署、扩展和管理。
-
Red Hat OpenShift:基于 Kubernetes 构建的容器应用平台。
-
Apache Mesos / Mesosphere DC/OS:分布式系统内核,支持高效地管理数据中心资源并运行容器化的服务。
-
LXC (Linux Containers):一种轻量级的操作系统级别虚拟化方法,在单一Linux内核上创建隔离的用户空间。
以上列举的是一部分在不同场景下广泛应用的虚拟化工具,随着时间推移和技术发展,新的工具和平台也会不断出现。
2、为什么学习docker
某公司的产品运行在内部的虚拟化平台中,如openstack, 也就是我们所学的KVM虛拟化,创建虚拟机。
什么是OpenStack
OpenStack 是一个开源的云计算平台【管理多个虚拟机平台】,它由一组软件工具组成,这些工具共同协作来提供可扩展且灵活的基础架构即服务(IaaS)。通过OpenStack,用户能够管理并控制数据中心内的大量计算、存储和网络资源,并将其作为统一的云环境进行部署和管理。OpenStack允许组织搭建、管理和提供私有云或公共云服务,使得用户能够根据需求快速调配虚拟机、存储卷和网络资源。
OpenStack的核心服务组件包括以下几个主要项目:
- Nova - 负责计算资源的调度和服务,如创建、调整和管理虚拟机实例。
- Neutron - 提供网络功能,包括虚拟网络、子网、路由器、负载均衡器等。
- Cinder - 提供块存储服务,为虚拟机提供持久化的块级存储卷。
- Swift 或 Ceph Object Storage - 提供对象存储服务,用于大规模、高可用性的数据存储。
- Keystone - 作为身份服务,负责认证、授权和多租户管理。
- Glance - 管理虚拟机镜像,确保虚拟机模板的注册、检索和分发。
此外,还有许多其他支持性服务和组件,如Heat(编排服务)、Horizon(Web界面仪表盘)以及其他针对特定场景优化的功能模块。OpenStack的设计旨在实现高度可定制化,以适应不同规模和复杂度的云基础设施需求。自2010年开源以来,OpenStack已发展成为一个活跃的全球性社区项目,吸引了众多企业和开发者参与贡献与使用。
但是不断增加的云端应用,增加了对硬件资源的消耗,不断的创建虚拟机,给公司带来了难题,公司已经在云平台上运行了多台云主机,消耗了大量的硬件资源。
怎么才能够高效的利用硬件资源实现云服务呢?
容器技术
Docker最初是DotCloud公司在法国期间发起的一个公司内部项目,后来以Apache2.0授权协议开源,代码在Github上维护。
Docker是基于Google公司推出的Golang语言开发而来,基于Linux内核的Cgroups、 NameSpace,以及UnionFS等技术,对进程进行封装隔离,属于操作系统层面的虛拟化技术。
由于隔离的进程独立于宿主机和其他隔离的进程,也被称之为容器。
最初的Docker是基于LXC的,后来去除LXC转而使用自行开发的Libcontainer。
容器和虚拟机的差异
传统虚拟机技术
虚拟机是虚拟出一套硬件,在其上面运行一个完整的操作系统,例如我们使用KVM,指定系统镜像,然后装系统,最终可以使用,在该系统上再运行所需的应用程序。
KVM创建虚拟机时,指定较少的cpu,内存,硬盘等资源,虚拟机性能较低。
容器技术
容器内的应用程序直接运行在宿主机的内核上,容器内没有自己的内核,也没有对硬件进行虚拟,因此容器比起虚拟机更为轻便。
容器对比KVM的好处
●容器能够提供宿主机的性能,而kvm虚拟机是分配宿主机硬件资源,性能较弱。
●同样配置的宿主机,最多可以启动10个虚拟机的话,可以启动100+的容器数量。
●启动一个KVM虚拟机,得有一个完整的开机流程,花费时间较长,或许得20S,而启动一个容器只需要1S。
●KVM需 要硬件CPU的虚拟化支持, 而容器不需要。
3、传统项目开发部署测试方式
4、通过docker容器进行项目部署
5、为什么选择docker
docker更高效的利用系统资源
容器不需要进行硬件虚拟化以及运行一个完整操作系统的额外开销,docker对系统资源的利用率更高,无论是应用执行,文件存储,还是在内存消耗等方面,都比传统虚拟机更高效。
因此一个同样配置的主机,可以运行处更多数量的容器实例。
更快的启动时间
传统的虚拟机启动时间较久,docker容 器直接运行在宿主机的内核.上,无须启动一个完整的操作系统,因此可以达到秒级启动,大大的解决开发,测试,部署的时间。
一致性的环境
在企业里,程序从开发环境,到测试服务器,到生产环境,难以保证机器环境一致性, 极大可能出现系统依赖冲突,导致难以部署等Bug。
然而利用docker的容器镜像技术,提供了除了内核以外完整的运行时环境,确保了应用环境的一致性。
持续交付和部署
还是刚才所说的一致性的环境,对于开发和运维的人员,最希望的就是环境部署迁移别处问题,利用docker可以定制镜像,以达到持续集成,持续交付和部署。
通过Dockerfile来进行镜像构建,实现系统集成测试,运维进行生产环境的部署。
且Dockerfile可以使镜像构建透明化,方便技术团队能够快速理解运行环境部署流程。
更轻松的迁移
Docker可以在很多平台运行,无论是物理机,虚拟机,云服务器等环境,运行结果都是一致的。
用于可以轻松的将一个平台的应用,迁移到另一个平台,而不用担心环境的变化,导致程序无法运行。
6、docker能做什么
- 可以把应用程序代码及运行依赖环境打包成镜像,作为交付介质,在各环境部署。
- 可以将镜像(image) 启动成为容器(container), 并且提供多容器的生命周期进行管理(启、停、删)。
- container容 器之间相互隔离,且每个容器可以设置资源限额。
- 提供轻量级虚拟化功能,容器就是在宿主机中的一个个的虚拟的空间,彼此相互隔离,完全独立。
7、docker VS 传统虚拟机
8、docker使用情况
Google从2004年起就已经开始使用容器技术了,并于2006年发布了Cgroups 和Imctfy项目。
Imctfy 是Google开源版本的容器栈,它提供了用来代替LXC的Linux应用容器。
Google云平台的高级软件工程师Joe Beda于2014年在Gluecon 上做了一个关于Google如何使用Linux容器技术的报告。
报告中声称现在Google所有的应用都是运行在容器中的。
Google每周要启动超过20亿个容器,每秒钟要启动超过3000个容器,这还不包括那些长期运行的容器。
Google 同样也正在将容器集成到Google云平台中。
Google于2014年推出了开源容器集群管理系统一Kubermetes, Kubernetes 就构建在Docker之上。
9、企业与容器集群
京东容器集群
2013年,京东弹性云从KVM起步。京东弹性云首先应用于京东私有云上。在选择Docker之前,尝试了KVM虛拟化方案,各方反馈性能不够好,无法满足大促的需求。
2014年10月,京东开始思考用Docker重构,在2014年底,决定采用Docker容器化方案,通过基于Docker 镜像的方式进行发布,其快速的弹性伸缩能力适合京东的大规模生产需求,并且其具备轻量、高性能和便捷性的优势。京东首先使用图片系统来验证其性能和弹性伸缩能力。之后再逐步推广到如单品页这样的核心系统,并进行网络的优化,以满足京东应用的性能,京东容器架构如图1-1-3所示。
架构图
淘宝容器集群
T4是阿里在2011年的时候基于LinuxContainer ( LXC )开发的容器技术基础设施。
T4是从阿里内部的资源管理和日常运维中土生土长出来的产品,在诞生的第一天就针对
内部基础设施、运维工具甚至运维习惯做了很多特别的设计。
阿里从2015年开始对Docker和T4做了一些修改整合后,将两者融合为了一个产品,相当于既让T4具备了Docker的镜像能力,又让Docker具备了T4具有的对内部运维体系的友好性,并且能够运行在内部的AliOS5u7和2.6.32内核上。这个产品在阿里内部称为AliDocker,如图1-1-4所示。
阿里成立专门的项目组推进docker应用,目标是把双11流量覆盖的核心应用,全部升级为镜像化的Docker应用。
二、Docker安装部署
1、Docker引擎
Docker Engine是C/S架构的
Docker由已下几个部件组成。
Docker Daemon
安装使用Docker,得先运行Docker Daemon进程,用于管理docker,如:
- 镜像images
- 容器containers
- 网络network
- 数据卷Data Volumes
Rest接口
提供和Daemon交互的API接口
Docker Client
客户端使用REST API和Docker Daemon进行访问。
Docker平台组成
Images
镜像是一个只读模板,阴于创建容器,也可以通过Dockerfile文本描述镜像的内容。
镜像的概念类似于编程开发里面向对象的类,从-一个基类开始(基 础镜像Base Image)
构建容器的过程,就是运行镜像,生成容器实例。
Docker镜像的描述文件是Dockerfile,包含了如下的指令
- FROM定义基础镜像
- MAINTAINER 作者
- RUN运行Linux命令
- ADD添加文件/目录
- ENV环境变量
- CMD运行进程
Container
容器是一个镜像的运行实例,镜像>容器。
创建容器的过程
- 获取镜像,如docker pull centos ,从镜像仓库拉取
- 使用镜像创建容器
- 分配文件系统,挂载一个读写层,在读写层加载镜像
- 分配网络/网桥接口,创建一个网络接口,让容器和宿主机通信
- 容器获取IP地址
- 执行容器命令,如/bin/bash
- 反馈容器启动结果。
Registry
Docker镜像需要进行管理,docker提供 了Registry仓库,其实它也是一个容器。
可以用于可以基于该容器运行私有仓库。
也可以使用Docker Hub互联网公有镜像仓库。
2、Docker介绍
版本管理
- Docker引擎主要有两个版本:企业版(EE) 和社区版(CE)
- 每个季度(1-3,4-6,7-9,10-12), 企业版和社区版都会发布一个稳定版本(Stable)。社区版本会提供4个月
的支持,而企业版本会提供12个月的支持 - 每个月社区版还会通过Edge方式发布月度版
- 从2017年第一季度开始,Docker版本号遵循YY.MM-xx格式,类似于Ubuntu等项目。例如,2018
年6月第一-次发布的社区版本为18.06.0-ce
13年成立,15年开始,迎来了飞速发展。
Docker 1.8之前,使用LXC,Docker在 上层做了封装,把L XC复杂的容器创建与使用方式简化为自己的一套命令体系。
之后,为了实现跨平台等复杂的场景,Docker抽 出了libcontainer项目,把对namespace、 cgroup的操作封装在libcontainer项目里,支持不同的平台类型。
2015年6月,Docker牵头成立了OCI (Open Container Initiative开 放容器计划)组织,这个组织的目的是建立起一个围绕容器的通用标准。
容器格式标准是一种不受上层结构绑定的协议,即不限于某种特定操作系统、硬件、CPU架构、公有云等,允许任何人在遵 循该标准的情况下开发应用容器技术,这使得容器技术有了一个更广阔的发展空间。
OCI成立后,libcontainer 交给OCI组织来维护,但是libcontainer中只包含了与kernel交互的库,因此基于libcontainer项目,后面又加入了一个CL工具,并且项目改名为runC
(https://github.com/opencontainers/runc),目 前runC已经成为一个功能强大的runtime工具 。
Docker也做了架构调整。将容器运行时相关的程序从docker daemon剥离出来,形成了containerd
。
containerd
向上为Docker Daemon
提供了gRPC接口 ,使得Docker Daemon屏蔽下面的结构变化,确保原有接口向下兼容。向下通过containerd-shim
结合runC
,使得引擎可以独立升级,避免之前Docker Daemon升级会导致所有容器不可用的问题。
也就是说
- runC (libcontainer) 是符合OCI标准的一一个实现,与底层系统交互。
- containerd是实现了OCI之.上的容器的高级功能,比如镜像管理、容器执行的调用等。
- Dockerd目 前是最上层与CLI交互的进程,接收cli的请求并与containerd协作。
小结
- 为了提供-种更加轻量的虚拟化技术,docker出现了
- 借助于docker容器的轻、快等特性,解决了软件交付过程中的环境依赖问题,使得docker得 以快速发展
- Docker是-种CS架构的软件产品,可以把代码及依赖打包成镜像,作为交付介质,并且把镜像启动成
为容器,提供容器生命周期的管理 - docker-ce,每季度发布stable版本。18.06, 18.09, 19.03
5.发展至今,docker已经 通过制定OCI标准对最初的项目做了拆分,其中runC和containerd是docker的核
心项目,理解docker整个请求的流程,对我们深入理解docker有很大的帮助
3、安装环境初始化
- App A、App B、App C和App D:这些是应用程序层,代表不同的应用软件。
- Bins/Libs:这是二进制文件和库文件层,包含应用程序所需的可执行文件和库文件。
- Docker:这是容器层,表示使用Docker技术进行的应用程序隔离和封装。
- Guest OS:这是客户操作系统层,每个应用程序或容器都运行在自己的操作系统实例上。
- Hypervisor:这是虚拟机管理程序层,负责管理和调度硬件资源,并为多个Guest OS提供虚拟化的硬件环境。
- Infrastructure:这是基础设施层,包括物理服务器、网络设备等硬件资源。
机器环境初始化
1、将阿里云提供的CentOS 7的YUM仓库配置下载并覆盖到本地系统的仓库配置文件中,从而实现将系统软件源更换为阿里云的镜像源。
wget -O /etc/yum.repos.d/Centos-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
在Centos 7 当中运行
2、将阿里云提供的EPEL 7的YUM仓库配置下载并替换到本地系统的EPEL仓库配置文件中,使得系统能够通过阿里云的镜像源来访问和安装EPEL仓库中的额外软件包,从而提高国内用户的下载速度和稳定性。
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
3、yum clean all 在基于RPM的Linux系统(如CentOS、Red Hat等)中用于清理YUM缓存和相关数据。
yum clean all
4、执行 yum makecache 时,YUM工具将根据 /etc/yum.repos.d/ 目录下的仓库配置文件获取各个仓库的URL,然后下载这些仓库的最新repomd.xml以及其他描述软件包及其版本状态的文件。
yum makecache
5、将删除系统中当前配置的所有防火墙规则,使得所有的数据包都将根据内核的默认策略进行处理
iptables -F
6、SELinux是否启用及其工作模式
getenforce
getenforce 是在基于SELinux(Security-Enhanced Linux)的Linux系统中用来查询当前SELinux策略执行状态的命令。
SELinux是一种强制访问控制(MAC)机制,提供了额外的安全层以增强系统的安全性。
当运行 getenforce 命令时,它会返回当前SELinux的运行模式:
Enforcing:表示SELinux正在执行其安全策略,对系统中的进程和文件系统资源进行严格控制。
Permissive:表示SELinux虽然在运行,但仅记录违反安全策略的行为而不阻止它们,相当于 SELinux 的“警告模式”。
Disabled:表示SELinux已经被禁用,此时系统不执行任何SELinux相关的安全策略。
通过这个命令,管理员可以快速了解SELinux是否启用及其工作模式,以便根据需要调整系统的安全设置。
7、安装一些常用的工具
yum install -y bash-completion vim lrzsz wget expect net-tools nc nmap tree dos2unix htop iftop iotop unzip telnet sl psmisc nethogs glances bc ntpdate openldap-devel -y
9、关闭防火墙
禁用开机启动防火墙
systemctl disable firewalld
停止当前正在运行的防火墙
systemctl stop firewalld
4、配置网卡转发
docker必须安装在centos7平台, 内核版本不低于3.10
在centos平台运行docker可能会遇见些告警信息,修改内核配置参数,打开内核转发功能
#写入
开启Linux内核的流量转发
cat <<EOF > /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.ip_forward=1
EOF
运行 modprobe br_netfilter 命令时,实际上是通知操作系统加载这个内核模块,以便为网桥提供网络过滤功能。
modprobe br_netfilter
加载修改内核的参数
sysctl -p /etc/sysctl.d/docker.conf
利用yum快速安装docker
用户实际上是替换或添加一个新的YUM源配置到他们的系统中,以使用阿里云提供的CentOS 7软件仓库作为下载和更新软件包的来源。
curl -O /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo
通过执行这个命令,用户将阿里云的Docker CE仓库添加到了他们的系统中,以便后续能够通过YUM包管理器安装、更新或管理Docker CE相关的软件包。使用阿里云的镜像源通常可以提高在中国地区的下载速度和稳定性。
curl -O /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
更新yum缓存
yum clean all && yum makecache
如何可以直接使用yum安装docker
##查看源中可用版本
yum list docker-ce --showduplicates | sort -r
yum install docker-ce-20.10.6 -y
安装完成
卸载对应docker
yum remove docker-ce-20.10.6
5、配置docker镜像加速器
使用docker首要操作就是获取镜像文件,默认下载是从Docker Hub下载,网速较慢,国内很多云服务商都提供了加速器服务,阿里云加速器,Daocloud加速器, 灵雀云加速器。
修改docker配置文件,我们选用七牛云镜像站
mkdir -p /etc/docker/
touch /etc/docker/daemon.json
vim /etc/docker/daemon.json
{
"registry-mirrors":[
"https://8xpk5wnt.mirror.aliyuncs.com"
]
}
启动docker
systemctl daemon-reload
systemctl enable docker
systemctl restart docker
验证一下是否启动
ps -ef |grep docker
docker version
三、启动一个Docker容器
1、用docker运行nginx镜像
获取镜像,获取是从你配置好的docker镜像站中,去拉取nginx镜像
先搜索一下,镜像文件
docker search nginx
拉去下载镜像
docker pull nginx
docker image ls
删除对应的镜像 docker rmi 镜像id
docker rmi 605c77e624dd
再次拉去镜像
docker pull nginx
在Docker中,镜像通常由多个层组成,这样可以共享公共的父层,并且只存储差异的部分,从而节省存储空间。
当拉取镜像时,Docker会下载所有需要的层,然后组合成一个完整的镜像。
查看系统端口占用情况,我们看到80端口被占用
netstat -tunlp
运行镜像的命令,运行出,具体的容器,然后这个容器中,就跑着一个nginx服务了
运行镜像的命令,参数如下
docker run 参数 镜像的名称/id
我们通过8080端口启动nginx
# -d 后台运行的容器
# -p 80:80 端口映射、宿主机端口:容器内端口 ,你访问宿主机这个端口,也就访问到了容器内的端口
docker run -d -p 8080:80 nginx
返回容器的id
查看当前正在运行的镜像
docker ps
此时可以访问宿主机的8080端口,查看到容器内的80端口的应用是什么了
http://192.168.180.128:8080/
2、用docker停止nginx镜像
docker stop 容器id
查看正在运行docker镜像
docker ps
停止运行对应的镜像
docker stop 83408dbafa47
再次访问:http://192.168.180.128:8080/
我们再次运行镜像
docker start 83408dbafa4
http://192.168.180.128:8080/
四、彻底学明白docker镜像的原理
我们来解释一下拉取镜像的时候发生了什么
通过docker images查看下载好的镜像
docker images
我们发现Redis的镜像是113MB比正常的Redis安装包要大的多
五、我们用的centos7 系统张什么样子
我们一直以来,使用vmware虚拟机,安装的系统,是一个完整的系统文件,包括2部分
- linux内核,作用是提供操作系统的基本功能,和机器硬件交互
- centos7发行版, 作用是提供软件功能,例如yum安装包管理等
因此,linux内核 +centos发行版,就组成了一一个系统,让我们用户使用。
查看系统的2部分组成
centos发行版
cat /etc/redhat-release
linux内核
uname -r
是否有一个办法,可以灵活的替换发行版,让我们使用不同的[系统] ?
那么docker就实现了这个功能,技术手段就是docker images
六、快速实践,使用docker
来切换不同的发行版,内核使用的都是宿主机的内核
docker pull ubuntu
确认当前的宿主机发行版
运行上面的ubuntu的镜像
docker images
参数 解释 -i 交互式命令操作 -t 表示开启一个终端
docker run -it ba6acccedd29 bash
我们发现localhost变为了20d8d4f19fc7表面我们已经进入到了容器空间内的ubuntu操作系统了
cat /proc/version
退出容器系统
exit
现在想玩suse系统
docker pull opensuse
docker images
docker run -it opensuse bash
cat /etc/SuSE-release
退出系统
exit
七、理解什么是docker镜像
docker images 搜索地址
https://hub.docker.com
1、一个完整的docker镜像可以创建出docker容器的运行,例如一个centos:7.8.2003镜像文件,我们
获取的是centos7这个发行版,这个镜像文件是不包含linux内核的
如果你直接在宿主机上,安装这些工具,那受限于宿主机的环境可能有哪些麻烦
1.环境不兼容,比如软件需要运行在linux下,但是你是windows,只能去安装一个vmware虚拟机, 或者再去买- -个云服务器,安装
2.会将你当前系统的环境,搞的一团糟
3.比如你想卸载这些工具,麻烦了,不会卸载。
docker彻底解决了老王的问题,以后可以不加班了,没事去领居家看看嫂子。
还是老王的笔记本,windows
1、解决了环境的兼容问题,在容器中运行linux发行版,以及各种软件,[windows +docker+容器1 (centos) +容器2 (ubuntu) ]。
2、环境很干净,你安装的所有内容,都在容器里,不想要了,就直接删除容器,不影响你宿主机。
3、比如你想把mysq|容器内的数据,配置,全部迁移到服务器上,只需要提交该容器, 生成镜像,镜像放到服务器上,docker run,咔咔就运行了! ! !。
Union File System
docker通过联合文件系统,将上述的不同的每一层, 整合为-个文件系统,为用户隐藏了多层的视角。
小节:
- 当通过一个image启动容器时,docker会在该image最顶层, 添加一个读写文件系统作为容器,然后运行该容器。
- docker镜像本质是基于UnionFS管理的分层文件系统
- docker镜像为什么才几百兆?
答:因为docker镜像只有rotts和其他镜像层,共用宿主机的linux内核(botfs) ,因此很小! - 为什么下载一个docker的nginx镜像,需要133MB? nginx安装包不是才几兆吗?
答:因为docker的nginx镜像是分层的,nginx安装包的确就几M,但是一一个用于运行nginx的镜像文件, 依赖于父镜像(上一 层),和基础镜像(发行版),所以下载的nginx镜像有一百多兆。
我们安装了nginx的镜像,进入容器当中看一下
docker ps
进入nginx的容器当中
docker exec -it 83408dbafa47 bash
cat /etc/os-release
我们看到nginx依赖一个基础镜像Debian
我们如果自定义镜像,刚才已经和大家说了,docker镜像不包含linux内核,和宿主机共用。
我们如果想要定义一个mysql5.6镜像,我们会这么做
- 获取基础镜像,选择一个发行版平台(ubutu, centos)
- 在centos镜像 中安装mysql5.6软件
导出镜像,可以命名为mysql:5.6镜像文件。
从这个过程,我们可以感觉出这是一层一层的添加的,docker镜像的层级概念就出来了,底层是centos镜像,上层是mysql镜像,centos镜像层 属于父镜像。
Docker镜像是在基础镜像之后,然后安装软件,配置软件,添加新的层,构建出来。
这种现象在学习dockerfile构建时候,更为清晰。
八、Docker为什么分层镜像
镜像分享一大好处就是共享资源,例如有多个镜像都来自于同一个base镜像,那么在docker host只需要存储一份base镜像。
内存里也只需要加载一份host,即可为多个容器服务。
即使多个容器共享一个base镜像, 某个容器修改了base镜像的内容,例如修改/etc/ 下配置文件,其他容器的/etc/下内容是不会被修改的,修改动作只限制在单个容器内,这就是容器的写入时复制特性(Copy-on-write )
docker当中多个容器在运行的时候使用的基础镜像都是是同一个吗,只需要加载一次?
在Docker中,确实可以基于同一个基础镜像运行多个容器。当你从一个镜像启动多个容器时,这个基础镜像不需要多次加载。Docker采用的是联合文件系统(UnionFS)机制,这意味着每个镜像的所有层在首次拉取或构建后都会被存储在宿主机上。后续创建容器时,Docker会复用这些现有的镜像层,而不是重新加载或复制整个镜像。
因此,当您基于同一个镜像启动多个容器时,所有容器共享该镜像的文件系统层,只有在容器启动时产生的差异数据才会存储在容器自己的可写层中。这样设计极大地节省了存储空间,并且提高了容器实例化的效率。所以答案是肯定的,对于多个容器来说,只需加载一次基础镜像即可。
1、可写的容器层
当容器启动后,一个新的可写层被加载到镜像的顶部,这一层通常被称为容器层,容器层下的都称为镜像层。
所有对容器的修改动作,都只会发生在容器层里,只有容器层是可写的,其余镜像层都是只读的。
只有当需要修改时才复制一份数据,这种特性被称作Copy-on-Write。
可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
docker ps
列出所有在运行的容器信息。
进入到容器内容部
docker exec -it 83408dbafa47 bash
进入opt目录
cd opt/
创建 a.txt文件
touch a.txt
在容器当中删除对应的内容
cd /etc/
rm -rf issue
2、Docker镜像的内容
docker镜像层级管理的方式大大便捷了Docker镜像的分发和存储。Docker hub是为全世界的镜像仓库。
- Docker镜像代表一 个容器的文件系统内容
- 镜像层级技术属于联合文件系统
- 容器是一个动态的环境,每一层镜像里的文件都属于静态内容,
- dockerfile里 的ENV、VOLUME、CMD等内容都会落实到容器环境里
UnionFS
这样设计的好处
1.下载安装docker工具
2.获取该软件的docker镜像(你以后想要用的各种工具,基本上都能够搜索到合适的镜像去用),下载nginx镜像,docker pull nginx
3.运行该镜像,然后就启动了一-个容器,这个nginx服 务就运行在容器中
4.停止容器,删除该镜像,哦了,你的电脑上,好像就没有使用过nginx-样
就好比沙箱一样的环境
基于镜像的增删改查维护
九、获取镜像
1、获取镜像,镜像托管仓库,好比yum源一样
默认的docker仓库是,dockerhub ,有大量的优质的镜像,以及用户自己, 上传的镜像centos容器
vim nginx
提交为镜像,上传到dockehub
-it开启一个交互式的终端 --rm 容器退出时删除该容器
docker run -it centos bash
docker images
指定对应的版本运行对应的centos:7
docker run -it --rm centos:7 bash
查看具体的镜像
docker images centos
docker images ubuntu
docker images nginx
docker images centos:7
只列出镜像的id
q --quiet 只列出id
docker images -q
十、Docker的常用命令
1、帮助命令
docker version # 显示docker的版本信息
docker info # 显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help # 帮助命令
帮助文档的地址:Reference documentation | Docker Documentation
2、镜像命令
2.1 docker images
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的id
CREATED 镜像的创建时间
SIZE 镜像的大小
命令参数可选项
-a, --all # 显示所有镜像 (docker images -a)
-q, --quiet # 仅显示镜像id (docker images -q)
2.2 docker search(搜索镜像)
解释
命令参数可选项 (通过搜索来过滤)
–filter=STARS=3000 # 搜索出来的镜像就是stars大于3000的
2.3 docker pull(下载镜像)
# 下载镜像:docker pull 镜像名[:tag]
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker pull mysql
Using default tag: latest # 如果不写tag,默认就是latest,最新的版本
latest: Pulling from library/mysql
72a69066d2fe: Pull complete # 分层下载,docker image的核心,联合文件下载
93619dbc5b36: Pull complete
99da31dd6142: Pull complete
626033c43d70: Pull complete
37d5d7efb64e: Pull complete
ac563158d721: Pull complete
d2ba16033dad: Pull complete
688ba7d5c01a: Pull complete
00e060b6d11d: Pull complete
1c04857f594f: Pull complete
4d7cfa90e6ea: Pull complete
e0431212d27d: Pull complete
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709 #签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址
# 两个命令是等价的
docker pull mysql
docker pull docker.io/library/mysql:latest
# 指定版本下载
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
72a69066d2fe: Already exists # 联合文件下载,已经存在的资源可以共用
93619dbc5b36: Already exists
99da31dd6142: Already exists
626033c43d70: Already exists
37d5d7efb64e: Already exists
ac563158d721: Already exists
d2ba16033dad: Already exists
0ceb82207cd7: Pull complete
37f2405cae96: Pull complete
e2482e017e53: Pull complete
70deed891d42: Pull complete
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
2.4 docker rmi(删除镜像)
[root@JWei_0124 //]# docker rmi -f 镜像id # 删除指定的镜像
[root@JWei_0124 //]# docker rmi -f 镜像id 镜像id 镜像id # 删除多个镜像(空格分隔)
[root@JWei_0124 //]# docker rmi -f $(docker images -aq) # 删除全部的镜像
3、容器命令
说明:我们有了镜像才可以创建容器,linux,下载一个centos 镜像来测试学习。
docker pull centos
3.1、新建容器并启动
docker run [可选参数] image
# 参数说明
--name="name" 容器名字:用来区分容器
-d 后台方式运行:相当于nohup
-it 使用交互式运行:进入容器查看内容
-p 指定容器的端口(四种方式)小写字母p
-p ip:主机端口:容器端口
-p 主机端口:容器端口
-p 容器端口
容器端口
-P 随机指定端口(大写字母P)
# 测试:启动并进入容器
[root@JWei_0124 module]# docker run -it centos /bin/bash
[root@f8fad61a6c96 /]# ls # 查看容器内的centos(基础版本,很多命令都是不完善的)
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
# 从容器中退回到主机
[root@f8fad61a6c96 /]# exit
exit
[root@JWei_0124 module]#
[root@JWei_0124 /]# ls
bin boot dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var www
3.2、列出所有运行的容器
docker ps # 列出当前正在运行的容器
# 命令参数可选项
-a # 列出当前正在运行的容器+历史运行过的容器
-n=? # 显示最近创建的容器(可以指定显示几条,比如-n=1)
-q # 只显示容器的编号
[root@JWei_0124 //]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@JWei_0124 //]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8fad61a6c96 centos "/bin/bash" 2 minutes ago Exited (0) About a minute ago epic_greider
b4b5e50d9889 centos "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago suspicious_mendeleev
321c5e25bca9 feb5d9fea6a5 "/hello" 2 hours ago Exited (0) 2 hours ago wonderful_saha
[root@JWei_0124 //]# docker ps -a -n=1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8fad61a6c96 centos "/bin/bash" 2 minutes ago Exited (0) About a minute ago epic_greider
[root@JWei_0124 //]#
3.3、退出容器
exit # 容器直接停止,并退出
ctrl+P+Q # 容器不停止,退出
[root@JWei_0124 //]# docker run -it centos /bin/bash //交互式进入
[root@68b68a9576e0 /]# [root@JWei_0124 //]# //按快捷键 自动输入
[root@JWei_0124 //]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
68b68a9576e0 centos "/bin/bash" 2 minutes ago Up 2 minutes peaceful_jemison
[root@JWei_0124 //]#
3.4、删除容器
docker rm 容器id # 删除容器(不能删除正在运行的容器)如果要强制删除:docker rm -f 容器id
docker rm -f $(docker ps -aq) # 删除全部容器
docker ps -a -q|xargs docker rm # 删除所有容器
3.5、启动和停止容器的操作
docker start 容器id # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止当前正在运行的容器
docker kill 容器id # 强制停止当前容器
4、常用其他命令
4.1 后台启动容器
# 命令docker run -d 镜像名
[root@JWei_0124 //]# docker run -d centos
5b06d0d14b3312e589a411dd9ae15589dc9321f771e5615b7ae26e85017de080
# 问题:docker ps发现centos停止了
# 常见的坑:docker容器使用后台运行,就必须要有要一个前台进程,docker发现没有应用,就会自动停止。
# 比如:nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了
4.2 查看日志
docker logs -tf --tail 容器id
# 自己编写一段shell脚本
docker run -d centos /bin/sh -c "while true;do echo kuangshen;sleep 1;done"
[root@JWei_0124 //]# docker logs -tf 容器id
[root@JWei_0124 //]# docker logs -tf --tail 10 容器id
# 显示日志
-tf # 显示日志
--tail number # 要显示的日志条数
4.3 查看容器中进程的信息
# 命令 docker top 容器id
[root@JWei_0124 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
25eb9d70b2b4 redis "docker-entrypoint.s…" About a minute ago Up About a minute 6379/tcp awesome_chatterjee
[root@JWei_0124 ~]# docker top 25eb9d70b2b4
UID PID PPID C STIME TTY TIME CMD
systemd+ 181442 181422 0 09:47 ? 00:00:00 redis-server *:6379
4.4 查看镜像的元数据
命令docker inspect 容器id
4.5 进入当前正在运行的容器
# 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置
# 命令
docker exec -it 容器id /bin/bash
# 测试
[root@JWei_0124 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
88d23bcbe1f2 centos "/bin/sh -c 'while t…" 13 minutes ago Up 13 minutes silly_lichterman
[root@JWei_0124 ~]# docker exec -it 88d23bcbe1f2 /bin/bash
[root@88d23bcbe1f2 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 08:23 ? 00:00:00 /bin/sh -c while true;do echo kuangshen;sleep 1;done
root 841 0 0 08:37 pts/0 00:00:00 /bin/bash
root 858 1 0 08:37 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
root 859 841 0 08:37 pts/0 00:00:00 ps -ef
# 方式二
docker attach 容器id
# 测试
[root@JWei_0124 ~]# docker attach 88d23bcbe1f2
正在执行当前的代码...
# docker exec # 进入容器后开启一个新的终端,可以再里面操作(常用)
# docker attach # 进入容器正在执行的终端,不会启动新的进程。
4.6 从容器内拷贝文件到主机
docker cp 容器id:容器内路径 目的主机的路径
[root@iZbp13qr3mm4ucsjumrlgqZ home]# ll
total 0
[root@iZbp13qr3mm4ucsjumrlgqZ home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZbp13qr3mm4ucsjumrlgqZ home]# docker run -it centos /bin/bash
[root@6eda31ad7987 /]# [root@iZbp13qr3mm4ucsjumrlgqZ home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6eda31ad7987 centos "/bin/bash" 17 seconds ago Up 16 seconds stoic_kepler
# 进入到容器内部
[root@iZbp13qr3mm4ucsjumrlgqZ home]# docker attach 6eda31ad7987
[root@6eda31ad7987 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@6eda31ad7987 /]# cd /home/
[root@6eda31ad7987 home]# ls
# 在容器的/home路径下创建test.java文件
[root@6eda31ad7987 home]# touch test.java
[root@6eda31ad7987 home]# ls
test.java
[root@6eda31ad7987 home]# exit
exit
[root@iZbp13qr3mm4ucsjumrlgqZ home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZbp13qr3mm4ucsjumrlgqZ home]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6eda31ad7987 centos "/bin/bash" About a minute ago Exited (0) 28 seconds ago stoic_kepler
# 将文件拷贝出来到主机上(在主机上执行该命令)
[root@iZbp13qr3mm4ucsjumrlgqZ home]# docker cp 6eda31ad7987:/home/test.java /home
[root@iZbp13qr3mm4ucsjumrlgqZ home]# ls
test.java
# 拷贝是一个手动过程,未来我们使用 -v 卷的技术,可以实现,自动同步(容器内的/home路径和主机上的/home路径打通)
十一、Docker镜像
1、镜像是什么
镜像是一种轻量级,可执行化的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件锁需要的所有内容,包括代码,运行时(库,环境变量和配置文件)
所有的应用 直接打包docker 镜像 就可以直接跑起来!
2、镜像加速原理
2.1 UnionFS(联合文件系统)
我们下载的时候看到的一层层就是这个!
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
2.2 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。
3、分层理解
分层镜像
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
Docker镜像要采用这种分层的好处?
资源共享 有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
所有的Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
简单来说 就是 原本有的 就共享 没有的咱就下载 更新了 就替换新的
特点:
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
4、commit镜像
#提交容器成为一个新的副本
docker commit
命令和git原理类似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]
1.启动一个默认的tomcat。
2.发现这个默认的tomcat是没有webapps应用,镜像的原因,官方的镜像默认webapps下面是没有文件的。
3.我自己拷贝进去了基本的文件。
4.将我们操作过的容器通过commit提交为一个镜像!我们以后就使用我们修改过的镜像即可,这就是我们自己的一个修改的镜像
小结: commit镜像就是游戏存档 tag是版本版本信息
十二、容器数据卷
1、什么是容器数据卷?
Docker容器数据卷,即Docker Volume(卷)。
当Docker容器运行的时候,会产生一系列的数据文件,这些数据文件会在关闭Docker容器时,直接消失的。但是其中产生部分的数据内容,我们是希望能够把它给保存起来,另作它用的。
关闭Docker容器=删除内部除了image底层数据的其他全部内容,即删库跑路
所以我们期望:
将应用与运行的环境打包形成容器运行,伴随着容器运行产生的数据,我们希望这些数据能够持久化。
希望容器之间也能够实现数据的共享、
- Docker容器产生的数据同步到本地,这样关闭容器的时候,数据是在本地的,不会影响数据的安全性。
- docker的容器卷技术也就是将容器内部目录和本地目录进行一个同步,即挂载。
总结: 容器的持久化和同步化操作,容器之间也是可以数据共享的(但是注意挂载不是等同于同步!!!)
2、使用数据卷
使用命令来挂载 -v
主机目录和容器内的目录是映射关系
docker run -it -v 主机目录:容器内目录 镜像名 /bin/bash
# 测试,查看容器信息
docker inspect 容器id
mounts 加载的文件系统
source 是源地址 就是 当前你这个docker里面的地址目录
destination 是 这个容器的目录
通过 -v挂载目录后 会对这个俩个目录中的数据进行 双向绑定(bind)
在容器的/home文件夹下,新建test.java文件,会同步到主机的/home/ceshi文件夹下。
删除操作也是同步的;双向绑定,保证两边文件夹下的数据始终是一直的。
停止容器后,在主机的/home/ceshi文件夹下,修改文件或新增文件,启动容器,查看容器的/home文件夹,发现容器内的数据依旧是同步的
1、停止容器。
2、宿主机上修改文件。
3、启动容器。
4、容器内的数据依旧是同步的。
好处:我们以后修改只需要在本地修改即可,容器内会自动同步!
3、安装MySQL
# 获取镜像
docker pull mysql:5.7
# 运行容器,需要做数据目录挂载。(安装启动mysql,注意:需要配置密码)
# 官方启动mysql
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
# 我们启动mysql(-e是环境配置)
[root@JWei_0124 home]# docker run -d -p 8081:3306
-v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:8.0.27
# 启动成功之后,我们在本地使用navicat来接测试一下。
# navicat连接到服务器的8081端口和容器内的3306映射,这个时候我们就可以连接上了!
# 在本地测试创建一个数据库,查看一下我们映射的路径是否ok!(OK的)
在navicat上 创建一个数据库
查看本地
现在 删除 容器
发现,我们挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化功能!
4、匿名挂载和具名挂载
# 匿名挂载
docker run -d -p --name nginx01 -v /etc/nginx nginx
# 查看所有的volume的情况
[root@JWei_0124 ~]# docker volume ls
DRIVER VOLUME NAME
local 964b8e505f12f65fb23fd21f05cfa9ecd6c2c6b2ca89c0e44f168bb017dfabd6
# 这种就是匿名挂载:我们在-v挂载目录时,只写了容器内的路径,没有写容器外的路径。
# 具名挂载
[root@JWei_0124 ~]# docker run -d -p 3344:80 --name nginx02 -v juming-nginx:/etc/nginx nginx
[root@JWei_0124 home]# docker volume ls
DRIVER VOLUME NAME
local 1be3512d772b7af8543c35141d5bbbfe29549dabf0babb7ce8693833387de41d
local 58ba3799ae59416c2b34d0672dfa848d158006f840bdb28b41ed463ed0a15599
# 通过 -v 卷名:容器内的路径(具名挂载)
# 查看一下这个卷
所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxxx/_data"(xxxx是卷名)
我们通过具名挂载可以方便的找到我们的一个卷,大多数情况在使用的具名挂载
# 如何确定是具名挂载,还是匿名挂载,还是指定路径挂载
-v 容器内的路径 # 匿名挂载
-v 卷名:容器内的路径 # 具名挂载
-v /宿主机路径:容器内路径 # 指定路径挂载
拓展
# 通过 -v 容器内的路径:ro rw 改变读写权限
ro read only # 只读
rw read write # 可读可写
# 一旦设置了容器权限,容器对我们挂载出来的内容就有了限定。
docker run -d -p 3344:80 --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -p 3344:80 --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
# 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作!
5、Dockerfile
dockerfile 就是用来构建 docker 镜像的构建文件。 命令脚本!
通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个一个的命令,每个命令都是一层!
# 创建一个dockerfile文件,名字可以随机,建议dockerfile
# 文件中的内容:指令都是大写
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "-----end-----"
CMD /bin/bash
# 这里的每个命令,就是镜像的一层。
启动容器
这个卷根外部一定有一个同步的目录!
查看一下卷挂载的路径:docker inspect 容器id
测试一下文件是否同步出去:在容器的volume01文件夹下创建文件,查看宿主机对应目录是否同步成功。
这种方式我们未来使用的十分多,因为我们通常会构建自己的镜像!
如果构建镜像时候没有挂载卷,就需要自己手动镜像挂载目录!
6、数据卷容器
多个容器同步数据(临时认父)
启动3个容器,通过我们刚才自己的写镜像启动。
三个容器的数据是 互相拷贝的 删除任意一个 其余的容器都可以看到那些数据 当然 所以的容器都删了 也就会删除了 除非做了持久化映射
多个mysql实现数据共享:
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker run -d -p 7777:3306 -v
/home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e
MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker run -d -p 7777:3306 -e
MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
# 这个时候,可以实现两个容器数据同步!
结论:
容器之间配置信息的传递,数据卷容器的生命同期一直持续到没有容器使用为止。
但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!
十三、DockerFile
1、什么是DockerFile ?
dockerfile是用来构建docker镜像的文件!命令参数脚本!
构建步骤:
1、编写一个dockerfile文件
2、docker build 构建成为一个镜像
3、docker run运行镜像
4、docker push发布镜像(DockerHub、阿里云镜像仓库!)
2、搭建步骤
1、每个保留关键字(指令)都是必须是大写字母
2、执行从上到下顺序执行
3、# 表示注释
4、每一个指令都会创建提交一个新的镜像层,并提交!
dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!
DockerFile:构建文件,定义了一切的步骤,源代码。
Dockerlmages:通过DockerFile构建生成的镜像,最终发布和运行的产品。
Docker容器:容器就是镜像运行起来提供服务的。
3、DockerFile的命令
FROM # 基础镜像,一切从这里开始构建
MAINTAINER # 镜像是谁写的:姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 步骤:tomcat镜像,这个tomcat压缩包!添加内容
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOSE # 暴露端口配置
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # 当构建一个被继承DockerFile这个时候就会运行ONBUILD的指令。触发指令。
COPY # 类似ADD,将我们文件拷贝到镜像中
ENV # 构建的时候设置环境变量!
4、测试
Docker Hub中99%镜像都是从这个基础镜像过来的FROM scratch,然后配置需要的软件和配置来进行的构建。
# 1. 编写dockerfile的文件
FROM centos:7
MAINTAINER sywl<xxx@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "-----end-----"
CMD /bin/bash
# 2. 通过这个文件构建镜像
# 命令:docker build -f dockerfile文件路径 -t 镜像名:[tag]
docker build -f mydockerfile-centos -t mycentos:0.1 .
Successfully built 285c2064af01
Successfully tagged mycentos:0.1
# 3. 测试运行
之前的原生的centos7:
我们增加之后的镜像:
我们可以列出本地进行的变更历史:docker history 镜像id
CMD和ENTRYPOINT区别
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
测试CMD
# 1. 编写dockerfile文件
[root@iZbp13qr3mm4ucsjumrlgqZ dockerfile]# vim mydockerfile-cmd-test
[root@iZbp13qr3mm4ucsjumrlgqZ dockerfile]# cat mydockerfile-cmd-test
FROM centos:7
CMD ["ls","-a"]
# 2. 构建镜像
[root@iZbp13qr3mm4ucsjumrlgqZ dockerfile]# docker build -f mydockerfile-cmd-test -t cmdtest .
# 3. run运行,发现我们的"ls -a"命令生效、执行
# 4. 我们先追加一个命令"l",构成"ls -al"命令,发现报错
[root@iZbp13qr3mm4ucsjumrlgqZ dockerfile]# docker run ec0d2dd226b3 -l
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled
# 原因:CMD命令的情况下,"-l"替换了CMD["1s","-a"]命令,因为"-l"不是命令,所以报错!
测试ENTRYPOINT
# 1. 编写dockerfile文件
[root@iZbp13qr3mm4ucsjumrlgqZ dockerfile]# vim mydockerfile-entrypoint-test
[root@iZbp13qr3mm4ucsjumrlgqZ dockerfile]# cat mydockerfile-entrypoint-test
FROM centos:7
ENTRYPOINT ["ls","-a"]
# 2. 构建镜像
[root@iZbp13qr3mm4ucsjumrlgqZ dockerfile]# docker build -f mydockerfile-entrypoint-test -t entrypointtest .
# 3. run运行,发现我们的"ls -a"命令生效、执行
# 4. 我们先追加一个命令"l",构成"ls -al"命令,发现命令生效、执行
# 原因:ENTRYPOINT命令的情况下,"-l"追加在ENTRYPOINT ["1s","-a"]命令后面,得到"ls -al"的命令,所以命令正常执行!
# (我们的追加命令,是直接拼接在我们的ENTRYPOINT命令的后面)
5、小结
十四、Docker 网络
1、docker0
清空所有的环境
测试
三个
问题:docker是如何处理容器网络访问的?
[root@JWei_0124 ~]# docker run -d -P --name tomcat01 tomcat
# 查看容器的内部网络地址ip addr,发现容器启动的时候会得到一个eth0@if119的ip地址(docker分配的)
[root@JWei_0124~]# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
118: eth0@if119: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 思考:liunx能不能ping通容器内部?(linux可以ping通容器内部)
[root@JWei_0124~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.059 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.046 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.057 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.045 ms
我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了ddcker,就会有一个网卡docker0
在启动一个容器测试 发现又多了一对网卡
所以 我们可以发现 容器带来的网卡 都是一对一对的
veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连。
正因为有这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备的。
openstack,Docker容器之间的连接,OVS的连接,都是使用veth-pair技术。
我们来测试下tomcat01和tomcat02是否可以ping通!(可以ping通)
[root@JWei_0124~]# docker exec -it tomcat02 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.055 ms
# 结论:容器和容器之间是可以互相ping通的!
绘制一个网络模型图
结论:tomcat01和tomcat02是公用的一个路由器,dockero。
所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用IP
Docker中的所有的网络接口都是虚拟的。虚拟的转发效率高!(内网传递文件!)
只要容器删除,对应网桥一对就没了!
2、link
高可用
我们编写了一个微服务,database url=ip:,项目不重启,数据库ip换掉了,我们希望可以处理这个问题,可以名字来进行访问容器?
# 通过服务名ping不通;如何解决?
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
# 通过--link可以解决网络连接问题。
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat:7.0
2393eecb870e5755068ea8b7d8bdcdd0f1ff110534c3359384413677c651bec4
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.085 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.055 ms
# 反向可以ping通吗?(不可以)
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
探究:docker network inspect networkID (docker network ls可以查看networkID)
# 查看
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker exec -it tomcat03 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.3 tomcat02 20398a94efa7
172.17.0.4 2393eecb870e
—link 就是我们在hosts配置中增加了一个”172.17.0.3 tomcat02 20398a94efa7”
我们现在玩Docker已经不建议使用—link了!
自定义网络!不适用docker0!
docker0问题:他不支持容器名连接访问!
3、自定义网络
查看所有的docker网络
网络模式
bridge:桥接 docker(默认,自己创建也使用bridge桥接模式)
none:不配置网络
host:和主机共享网络
container:容器网络连通!(用的少!局限很大)
测试
# 我们直接启动的命令--net bridge(这个就是我们的docker0);默认带上这个参数的,以下两种启动方式效果一致。
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcato1 --het bridge tomcat
# docker0特点:默认,域名不能访问,--1ink可以打通连接!
# 我们可以自定义一个网络!
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
7254ffccbdf5 bridge bridge local
45610891738f host host local
266acd66473c mynet bridge local
7795cbc2686c none null local
我们自己的网络就创建好了
[root@JWei_0124 ~]# docker run -d -P --name tomcat-net-01 --net mynet tomcat:7.0
[root@JWei_0124~]# docker run -d -P --name tomcat-net-02 --net mynet tomcat:7.0
# 不使用--link,ping名字也可以ping通。tomcat-net-01 ping tomcat-net-02可以ping通
[root@JWei_0124~]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.067 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.056 ms
# 不使用--link,ping名字也可以ping通。tomcat-net-02 ping tomcat-net-01可以ping通
[root@JWei_0124~]# docker exec -it tomcat-net-02 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.056 ms
我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络!
好处:
redis -不同的集群使用不同的网络,保证集群是安全和健康的
mysql -不同的集群使用不同的网络,保证集群是安全和健康的
4、网络连通
# tomcat01在docker0网络下,tomcat-net-01在mynet网络下;
# tomcat01 ping tomcat-net-01是ping不通的
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker exec -it tomcat01 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
连接网段
# 测试:打通tomcat01连接mynet
docker network connect mynet tomcat01
# 连通之后就是将tomcat01放到了mynet网络下
# 一个容器两个ip地址!I
# 阿里云服务:公网ip和私网ip
# 连接ok
[root@iZbp13qr3mm4ucsjumrlgqZ ~]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.065 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.052 ms