文章目录
1、Docker简介
1.1、是什么?
为什么会有Docker出现?
假定您正在开发一个项目,您使用的是一台笔记本并且你的开发环境具有特定的配置。其他开发人员身处的环境配置也各有不同。你正在开发的应用依赖于你当前的配置且还要依赖于某些配置文件。此外,你的企业还拥有标准化的测试和生产环境,且具有自身的配置和一系列支持文件。您希望尽可能多在本地模拟这些环境而不产生重新创建服务器环境的开销。请问?
你要如何确保应用能够在这些环境中运行和通过质量检测?并且在部署过程中不出现令人头疼的版本、配置问题,也无需重新编写代码和进行故障修复?
答案就是使用容器。Docker之所以发展如此迅速,也是因为它对此给出了一个标准化的解决方案——系统平滑移植,容器虚拟化技术。
环境配置相当麻烦,换一台机器,就要重新来一次,费时费力。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样的复制过来。开发人员利用Docker可以消除协作编码时“在我的机器上可以正常工作”的问题。
之前在服务器配置一个应用的运行环境,要安装各种软件,就拿尚硅谷电商项目的环境来说,Java/RabbitMQ/MySQL/JDBC驱动包等。安装和配置这些东西有多麻烦就不用说了,他还不能跨平台。加入我们是在Windows上安装的这些环境,到了Linux又得重新装。况且就算不跨操作系统,换另一台同样操作系统的服务器,要移植应用也是非常麻烦的。
传统上认为,软件编码开发/测试结束后,所产生的成果即是程序或是能够编译执行的二进制字节码等(Java为例)。为了让这些程序可以顺利执行,开发团队也得准备完整的部署文件,让运维团队得以部署应用测试,**开发需要清除的告诉运维部署团队,用的全部配置文件+所有软件环境。不过,即便如此,仍然常常发生部署失败的状况。**Docker的出现使得Docker得以打破过去【程序即应用】的观念。透过镜像(images)将作业系统核心除外,运作应用程式所需要的系统环境,由下而上打包,达到应用程式跨平台间的无缝接轨运作。
Docker理念
Docker是基于Go语言实现的云开源项目。
Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以使一个WEB应用或数据库应用等等)及其运行环境能够做到“一次镜像,处处运行”。
**Linux容器技术的出现就解决了这样一个问题,而Docker就是在它的基础上发展过来的。**将应用打成镜像,通过镜像成为运行在Docker容器上面的实例,而Docker容器在任何操作系统上都是一致的,这就是实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作。
一句话
Docker的出现解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
1.2、容器和虚拟机比较
容器发展简史
传统虚拟机技术
虚拟机(virtual machine)就是带环境安装的一种解决方案。
它可以在一种操作系统里边运行另一种操作系统,比如Windows10系统里面运行Linux系统CentOS7。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了解就删掉,对其他部分毫无影响。这类虚拟机完美的运行了另一套系统,能够使应用程序,操作系统和硬件三者之间的逻辑不变。
容器虚拟化技术
Linux容器(Linux Containers,缩写为LXC)
Linux容器是与操作系统其他部分隔离开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包含了应用的所有依赖项,因为在从开发再到生产的整个过程中,它都具有可移植性和一致性。
Linux容器不是模拟一个完整操作系统而是对进程进行隔离。有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一的运行。
对比
比较了Docker和传统虚拟化方式的不同之处:
- 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
- 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器也比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源。
1.3、能干嘛
技术职级变化
coder=>programmer=>software enineer=>DevOps engineer
开发/运维(DevOps)新一代开发工程师
一次构建,随处运行:
- 更快的应用交付和部署
- 传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行。Docker化之后只需要交付少量容器镜像文件,在正式生产环境加载镜像并运行即可,应用安装配置在镜像里已经内置好,大大节省部署配置和测试验证时间。
- 更便捷的升级和扩缩容
- 随着微服务架构和Docker的发展,大量的应用会通过微服务的方式架构,应用的开发构建将变成搭乐高积木一样,每个Docker容器将变成一块“积木”,应用的升级将变得非常容易。当现有的容器不足以支撑业务处理时,可通过镜像运行新的容器进行快速扩容,使应用系统的扩容从原来的天级变成分钟级甚至秒级。
- 更简单的系统运维
- 应用容器化运行后,生产环境运行的应用可与开发、测试环境的应用高度一致,容器会将应用程序相关的环境和状态完全封装起来,不会因为底层基础架构和操作系统的不一致性给应用带来影响,产生新的BUG。当出现程序异常时,也可以通过测试环境的相同容器进行快速定位和修复。
- 更高效的计算资源利用
- Docker是内核级虚拟化,其不像传统的虚拟化技术一样需要额外的Hypervisor支持,所以在一台物理机上可以运行很多个容器实例,可大大提升物理服务器的CPU和内存的利用率。
Docker的应用场景:
Docker借鉴了标准集装箱的概念。标准集装箱将货物运往世界各地,Docker将这个模型运用到自己的设计中,唯一不同的是:集装箱运输货物,而Docker运输软件。
1.4、去哪下
官网:www.docker.com
仓库:http://hub.docker.com
2、Docker安装
2.1、前提条件
CentOS Docker安装:
Docker并非是一个通用的容器工具,他依赖于已存在并运行的Linux内核环境。
Docker实质上是在已经运行的Linux下制造一个隔离的文件环境,因此他执行的效率几乎等同于所部署的Linux主机。
因此,Docker必须部署在Linux内核的系统上。如何其他系统想部署Docker就必须安装一个虚拟Linux环境。
在Windows上部署Docker的方法都是先安装一个虚拟机,并在安装linux系统的虚拟机中运行Docker。
前提条件:
目前,CentOS进发型版本中的内核支持Docker。Docker运行在CentOS7(64-bit)上,要求系统为64位、Linux系统内核版本为3.8以上,这里选用CentOS7.x。
查看自己的内核:
uname命令用于打印当前系统的相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。
2.2、基本组成
镜像(image)
Docker镜像(image)就是一个只读的模板。镜像可以用来创建Docker容器,一个镜像可以创建很多容器。它也相当于是一个root文件系统。比如官方镜像centos:7就包括了完整的一套centos:7最小系统的root文件系统。相当于容器的“源代码”,docker镜像文件类似于Java的类模板,而docker容器实例类似于Java中new出来的实例对象。
容器(container)
- 从面向对象角度
Docker利用容器(container)独立运行一个或者一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像Java中的类和实例对象一样,镜像是静态的定义,容器是静态运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,他可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
- 从镜像容器角度
可以吧容器看做是一个简易版的linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
仓库(repository)
仓库(Repository)是集中存放镜像的地方。
类似于:
- Maven仓库,存放各种jar包的地方。
- github仓库,存放各种git项目的地方。
- Docker公司提供的官方registry被称为Docker Hub,存放各种镜像模板的地方。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是Docker Hub:(https://hub.docker.com/)
存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云、网易云等。
小总结
需要正确的理解仓库、镜像、容器这几个概念:
Docker本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
image文件可以看做是容器的模板。Docker根据image文件生成容器的实例。同一个image文件,可以生成多个同时运行的容器实例。
镜像文件:
- image文件生成的容器实例,本身也是一个文件,称为镜像文件。
容器实例:
- 一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例,也就是我们的容器
仓库:
- 就是存放一堆镜像的地方,我们可以把镜像发布到仓库,需要的时候再从仓库拉下来就可以了。
2.3、架构图解
入门版
图解:
原理介绍:
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上,然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。容器,是一个运行时环境,就是我们前面所说的集装箱。可以对比mysql演示对比讲解。
架构版
首次听懵逼正常,后续深入,先有大概了解轮廓,混个眼熟。
整体架构及底层通信原理简述:
Docker是一个C/S模式的架构,后端是一个松耦合架构,众多模块各司其职。
Docker运行的基本流程为:
- 用户是使用Docker Client与Docker Daemon建立通信,并发送请求给后者。
- Docker Daemon作为Docker架构中的主体部分,首先提供Docker Server的功能使其可以接受Docker Client的请求。
- Docker Engine执行Docker内部的一系列工作,每一项工作都是以一个job的形式存在。
- job的运行过程中,当需要容器镜像时,则从Docker Registry中下载镜像,并通过镜像管理驱动Graph driver将镜像以Graph的形式存储。
- 当需要为Docker创建网络时,通过网络管理驱动Network driver创建并配置Docker容器网络环境。
- 当需要限制Docker容器运行资源或执行用户命令等操作时,则通过Exec driver来完成。
- Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来时实现具体对容器进行的操作。
2.4、安装步骤
安装文档:https://docs.docker.com/engine/install/centos/
确定你是Centos7及以上版本
命令:cat /etc/redhat-release
卸载旧版本
命令:
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
yum安装gcc相关
- 保证能上外网
sudo yum -y install gcc
sudo yum -y install gcc-c++
安装需要的软件包
命令:sudo yum install -y yum-utils
设置stable镜像仓库(有坑)
直接使用官网命令会报错,因为访问国外的服务器:
推荐:使用阿里云等提供的镜像仓库。
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
更新yum软件包索引
命令:sudo yum makecache fast
安装DOCKER CE
命令:sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
启动docker
命令:sudo systemctl start docker
测试
命令:sudo docker version
使用docker version命令能够打印出以下内容,表示docker安装启动成功。
使用helloworld测试:sudo docker run hello-world
卸载
依次运行以下命令:
systemctl stop docker
sudo yum remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
2.5、镜像加速器配置
地址:https://cn.aliyun.com/
注册一个账户,淘宝账户互通。
获得加速器链接(每个人都不同)。
最后根据不同系统的操作文档添加镜像地址
操作:
2.6、hello-world运行流程
2.7、为什么Docker比VM快
(1)docker有着比虚拟机更少的抽象层
由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
(2)docker利用的是宿主机的内核,而不需要加载操作系统OS内核
当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而Docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。
3、Docker常用命令
3.1、帮助启动类命令
- 启动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
3.2、镜像命令
docker images
- 功能:列出本地主机上的镜像。
- 命令:
docker images
各个选项说明:
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签版本号
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小
同一仓库可以有多个TAG版本,代表这个仓库源的不同个版本,我们使用REPOSITORY:TAG来定义不同的镜像。
如果你不指定一个镜像的版本标签,例如你只是用ubuntu,docker将默认使用ubuntu:latest镜像。
- OPTIONS说明:
-a:列出本地所有的镜像(含历史影像层)。
-q:只显示镜像ID。
docker search
- 功能:搜索某个xxx镜像的名称
搜索的网站:https://hub.docker.com(这里我们直接在阿里云拿了)
- 命令:
docker search [OPTIONS] 镜像名字
案例:
- OPTIONS说明:
–limit:只列出N个镜像,默认25个
docker search --limit 5 redis
docker pull
- 功能:下载某个xxx镜像
- 命令:
docker pull 镜像名字[:TAG]
docker pull 镜像名字
:没有TAG就是表示最新版,等价于docker pull 镜像名字:latest
案例:
docker system df
- 功能:查看镜像、容器、数据卷所占空间。
- 命令:
docker system df
案例:
docker rmi
- 功能:删除某个镜像。
- 命令:
docker rmi 某个xxx镜像名字ID
删除镜像:
删除单个:docker rmi -f 镜像ID
删除多个:docker rmi -f 镜像名1:TAG 镜像名2:TAG
删除全部:docker rmi -f $(docker images -qa)
案例:
面试题:谈谈docker虚悬镜像是什么?
- 是什么:仓库名、标签名都是的镜像,俗称虚悬镜像dangling image。
- 后续dockerfile章节再介绍。
思考
- 结合我们Git的学习心得,大家猜猜是否会有docker commit、docker push???
3.3、容器命令
前提
- 有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)。
本次演示用ubuntu演示:
新建/启动容器
命令:docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
- OPTIONS说明(常用):有些是一个减号,有些是两个减号
–name=“容器新名字” 为容器指定一个名称;
-d:后台运行容器并返回容器ID,也即启动守护式容器(后台运行);-i:以交互式模式运行容器,通常与-t同时使用;
-t:为容器重新分配一个伪输入终端,通常与-i同时使用;
也即启动交互式容器(前台有伪终端,等待交互);-P:随机端口映射,大写P
-p:指定端口映射,小写p
- 操作示例,创建一个交互式的ubuntu系统容器:
使用镜像ubuntu:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。
docker run -it ubuntu /bin/bash
参数说明:
-i:交互式操作。(interactive)
-t:终端。(tty)
ubuntu:ubuntu镜像。
/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式shell,因此使用的是/bin/bash。
要退出终端,直接输入exit;
列出当前所有正在运行的容器
- 命令:
docker ps [OPTIONS]
案例:
先运行一个ubuntu容器:
重开一个终端运行命令查看正在运行的容器:
重新运行一个主动分配名字的容器实例(myubuntu1):
重新开一个终端运行命令查看正在运行的容器:
- OPTINOS说明(常用):
-a:列出当前所有正在运行的容器+历史上运行过的
-l:显示最近创建的容器。
-n:显示最近n个创建的容器。
-q:静默模式,只显示容器编号。
案例:
退出容器
- 两种退出方式:
exit
:run进入容器,exit退出,容器停止。ctrl+p+q
:run进去容器,ctrl+p+q退出,容器不停止。
案例:
第一种情况:(exit)
- 开始没有任何运行的容器,然后run一个ubuntu容器,之后使用exit停止。
- 可以发现在exit之前ubuntu容器还存在,exit之后容器实例就消失了。
第二种情况:(ctrl+p+q)
- 运行一个ubuntu容器实例,然后使用ctrl+p+q退出。
- 发现退出后,容器实例仍然在运行。
启动已停止运行的容器
- 命令:
docker start容器ID或者容器名
重启容器
- 命令:
docker restart容器ID或者容器名
强制停止容器
- 命令:
docker kill容器ID或容器名
删除已停止的容器
- 命令:
docker rm 容器ID
一次性删除多个容器实例(不建议使用,太危险):
docker rm -f $(docker ps -a -q)
docker ps -a -q | xargs docker rm
案例:
删除单个容器:
删除多个容器:
重要
前提
- 有镜像才能创建容器,这是根本前提(下载一个Redis6.0.8镜像演示)
启动守护式容器(后台服务器)
- 注意:在大部分的场景下,我们希望docker 的服务是在后台运行的,我们可以通过-d指定容器的后台运行模式。
- 命令:
docker run -d 容器名
使用镜像ubuntu:latest以后台模式启动一个容器:docker run -d ubuntu
问题:然后docker ps -a进行查看,会发现容器已经退出。
很重要的要说明的一点:Docker容器后台运行,就必须有一个前台进程。
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如service nginx start。但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,这样容器后台启动后,会立即自杀因为他觉得他没事可做了。
所以,最佳的解决方案是:将你要运行的程序以前台进程的形式运行,常见的就是命令行模式,表示我还有交互操作,别中断,哈哈哈~~
- redis前后台启动案例:
- 前台交互式启动:
docker run -it redis:6.0.8
启动redis容器实例,然后关闭:
发现退出前后的状态,退出后容器也就停止运行了:
- 后台守护式启动:
docker run -d redis:6.0.8
使用后台启动redis,返回编号:
发现后台redis一直在运行:
查看容器日志
- 命令:
docker logs 容器ID
查看容器内运行的进程
- 我们在linux中可以使用top查看当前主机的运行的进程,而每个容器就是一个微小的内核,所以我们也可以使用top查看容器内部运行的进程。
- 命令:
docker top 容器ID
查看容器内部的细节
- 命令:
docker inspect 容器ID
进入正在运行的容器并以命令行交互
- 命令
docker exec -it 容器ID bashShell
docker attach 容器ID
- 区别
- attach:直接进入容器启动命令的终端,不会启动新的进程,用exit退出,会导致容器的停止。
- exec:是在容器中打开新的终端,并且可以启动新的进程,用exit退出,不会导致容器的停止。
- 推荐大家使用docker exec命令,因为退出容器终端,不会导致容器的停止。
案例:
- 操作后台redis容器实例
- 命令:
docker exec -it 容器ID bash
或docker exec -it 容器ID redis-cli
- 一般使用-d后台启动的程序,再用exec进入对应容器实例。
从容器内拷贝文件到主机上
- 容器->主机
- 命令:
docker cp 容器ID:容器内路径 目标主机路径
案例:
导入和导出容器(将容器创建一个镜像)
- export导出容器的内容留座位一个tar归档文件【对应import命令】
- import从tar包中的内容创建一个新的文件系统再导入为镜像【对应export】
- 命令:(将一个容器导出创建成一个镜像)
docker export 容器ID > 文件名.tar
cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
案例:
总结
4、Docker镜像
4.1、是什么
**镜像:**是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们吧应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例(类似java中new出来一个对象)。
4.2、分层的镜像
4.3、UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为依次提交来一层层的叠加,同时可以将不同目录挂在到同一虚拟文件系统下(unite servral directories into a single virtual filesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来继承,基于基础镜像(没有父镜像),可以制造各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
4.4、Docker镜像运行原理
Docker镜像加载原理:
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernal,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux、unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfd(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。
4.5、为什么docker镜像要采用这种分层结构呢?
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的base镜像构建而来,那么Docker Host只需要在磁盘上保存一份base镜像;
同时内存中也只需要加载一份base镜像,就可以为所有的容器服务了。而且镜像的每一层都可以被共享。
4.6、重点理解
Docker镜像层都是只读的,容器层是可写的
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作为“容器层”,“容器层”之下的都叫“镜像层”。
4.7、Docker commit命令
- 功能:提交容器副本使之成为一个新的镜像。
- 命令:
docker commit -m="提交的描述信息" -a="作者" 容器ID要创建的目录镜像名:[标签名]
案例:演示Ubuntu安装vim并使用commit创建本地镜像。
- 从Hub上下载ubuntu镜像到本地并成功运行
- 原始的默认ubuntu镜像是不带vim命令的
- 外网连通的情况下,安装vim
apt-get update # 先更新我们的包管理工具
apt-get -y install vim # 然后安装我们需要的vim
- 安装完成后,commit我们自己的新镜像。
- 启动我们的新镜像和原来的对比
案例:
第一步:
第二步:
第三步:
第四步:
第五步:
4.8、小总结
Docker中的镜像分层,支持通过拓展现有镜像,创建新的镜像。类似于java继承一个base基础类,自己再按需拓展。
新镜像是从base镜像一层一层堆叠生成的。每安装一个软件,就在现有镜像的基础上增加一层。
5、本地镜像发布到阿里云
5.1、本地镜像发布到阿里云流程
阿里云ECS Docker生态如下图所示:
5.2、镜像的生成方法
- 基于当前容器创建一个新的镜像,新功能增强。
docker commit [OPTIONS] 容器ID [REPOSITORY[:TAG]]
- 后面的DockerFile章节,第二种方法。
5.3、将本地镜像推送到阿里云
本地镜像素材原型
- 使用commit创建一个本地镜像素材
阿里云开发者平台
- 登录。
创建仓库镜像
- 选择控制台,进入容器镜像服务。
- 选择个人实例
- 创建命名空间
- 创建仓库名称
- 进入管理页面获取脚本
将镜像推送到远程库
- 将镜像推送到阿里云registry。
- 管理脚本界面。
- 脚本实例
5.4、将阿里云上的镜像下载到本地使用
- 使用命令将阿里云镜像拉到本地。
- 可以正常使用带有vim的Ubuntu了。
6、本地镜像发布到私有库
6.1、是什么-Docker Registry
- 官方Docker Hub地址:https://hub.docker.com,中国大陆访问太慢了且准别被阿里云取代的趋势,不太主流。
- Dockerhub、阿里云这样的公共镜像仓库可能不太方便,涉及机密的公司不可能提供镜像给公网,所以需要创建一个本地私人仓库供给团队使用,基于公司内部项目构建镜像。
- Dcoker Registry是官方提供的工具,可以用于构建私有镜像仓库。
6.2、将本地镜像推送到私有库
下载镜像Docker Registry
运行私有库Registry,相当于本地有个私有Docker hub
命令:docker run -d -p 5000:5000 -v /guoxiulong/myregistry/:/tmp/registry --privileged=true registry
- 默认情况下,仓库被创建在容器的/var/lib/registry目录下,建议自定使用容器卷映射,方便于宿主机联调。
案例演示创建一个新镜像,ubuntu安装ifconfig命令
- 最后将带有ifconfig命令的ubuntu创建为一个新镜像。
curl验证私服库上有什么镜像
命令:curl -XGET http://192.168.100.104:5000/v2/_catalog
- 可以发现当前没有任何镜像。
将新镜像修改为符合私服规范的Tag
公式:docker tag 镜像:TAG Host:Port/Repository:Tag
自己host主机IP地址,填写自己的,不要粘贴错误。
下面使用命令docker tag将ifconfig.1.1.0这个镜像修改为192.168.100.104:5000/ifconfig_ubuntu:1.2
修改配置文件使之支持http
vim命令新增如下第二行内容:vim /etc/docker/daemon.json
上述理由:docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。====>修改完后如果不生效,建议重启docker。
push推送到私服库
命令:docker push 192.168.100.104:5000/ifconfig_ubuntu:1.1.0
curl验证私服库上有什么镜像2
命令:curl -XGET http://192.168.100.104:5000/v2/_catalog
- 可以发现已经推送成功了
将私服库拉到本地测试
- 首先将之前的本地镜像删除
- 将私服库镜像拉到本地
- 运行镜像测试
7、Docker容器数据卷
7.1、坑
- 容器卷记得加入参数:
--privileged=true
- why?
Docker挂载主机目录访问如果出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个–privileged==true参数即可。
如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载情况被默认为不安全的行为,在SELinux里面挂载目录被禁止掉了,如果要开启,我们一般使用命令–privileged=true,扩大容器的权限解决挂载目录没有权限的问题,也即使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。
7.2、是什么
- 一句话:有点类似于我们Redis中的rdb和aof文件。
- 功能:将docker容器内的数据保存进宿主机的磁盘中。
- 运行一个带有容器卷存储功能的容器实例:****命令:
**docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名**
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持久存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存空间,因此Docker不会在容器删除时删除其挂载的数据卷。
7.3、能干嘛
- 将运用与运行的环境打包镜像,run后形成容器实例运行,但是我们对数据的要求希望是持久化的。
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然就没有了。
为了能保存数据在docker中我们使用卷。
特点:
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接实时生效,爽~~
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
7.4、容器卷的案例
宿主VS容器之间添加容器卷
直接命令添加:
- 命令:
**docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名**
- 查看数据卷是否挂载成功:
**docker inspect 容器ID**
- 测试容器和宿主机之间的数据共享。
- docker修改,主机同步获得
- 主机修改,docker同步获得
- docker容器stop,主机修改,docker容器重启看数据是否同步
下面测试前两种情况:
下面测试第三种情况:
读写规则映射添加说明
读写(默认):
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
- 默认同上案例,默认就是rw。
只读:
- 容器实例内部被限制,只能读取不能写。如果宿主机写入内容,可以同步给容器内,容器可以读取到。
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
卷的继承和共享
容器1完成和宿主机的映射:
容器2继承容器1的卷规则:
- 语法:
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu /bin/bash
关闭Ubuntu1容器查看容器ubuntu2的情况:
- 总结,–volumes-from继承的只是挂载规则,并不是将继承的容器直接作为父类。
8、Docker常规安装简介
8.1、总体步骤
搜索镜像
拉取镜像
查看镜像
启动镜像–服务端口映射
停止容器
移除容器
8.2、安装tomcat
docker hub上面查找tomcat镜像
但是官网速度太慢了,我们一般使用阿里云:
从docker hub上拉取tomcat镜像到本地
docker image查看是否拉取到tomcat
使用tomcat镜像创建容器实例(也叫运行镜像)
命令:docker run -it -p 8080:8080 tomcat
访问猫首页
访问猫首页的过程中可能会出错:
解决方案:
- 可能没有映射端口或者没有关闭防火墙
还是无法访问:
- 把webapps.dist目录换成webapps
访问成功:
免修改版说明
docker pull billygoo/tomcat8-jdk8
docker run -d -p 8080:8080 --name='mytomcat8' billygoo/tomcat8-jdk8
8.3、安装mysql
docker hub上面查找mysql镜像
阿里云搜索:
从docker hub上(阿里云加速器)拉取mysql镜像到本地标签为5.7
使用mysql5.7镜像创建容器(也叫运行镜像)
命令出处,哪里来的?
命令:**docker run --name some-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag**
简单版
- 使用mysql镜像
- 这里一定要加映射-p,不然后续远程连接会出问题,我这里没有加,在远程连接的时候重新创建的容器。
- 建库建表插入数据
- 外部Windows也来连接运行在docker上的mysql容器实例服务
重新创建容器,添加端口映射:
- 问题
问题一:插入中文会报错,因为docker上默认字符集编码隐患。
默认编码都是latin1,而不是utf8。
使用命令**show variables like '%char%'**
查看默认编码。
注意:一定要在原始环境中查询,不能远程使用navicat查询,不然结果可能不同。
问题二:删除容器后,里面的mysql数据如何办。
实战版
- 新建mysql容器实例
命令:docker run -d -p 3306:3306 --privileged=true -v /guoxiulong/mysql/log:/var/log/mysql -v /guoxiulong/mysql/data:/var/lib/mysql -v /guoxiulong/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=111111 --name='mysql' mysql:5.7
- 新建my.cnf
- 通过容器卷同步给mysql容器实例
[client]
default_character_set=utf8
[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8
- 重新启动mysql容器实例再重新进入并查看字符编码
- 再新建库建表插入中文测试
插入英文正常:
插入中文正常:
- 结论
- 修改字符集之后,之前的DB无效。
- 修改步骤:修改字符集操作+重启mysql容器实例。
- 之后的DB有效,需要新建库和表。
- 结论:docker安装完mysql并run出容器后,建议请先修改完字符集编码后再新建mysql库-表-插数据
- 加入将当前容器实例删除,再重新来一次,之前建的db01实例还有吗?
- 还有,因为数据也保存在宿主机上了。
测试:
8.4、安装redis
从docker hub上(阿里云加速器)拉取redis镜像到本地标签为6.0.8
入门命令
命令提醒:容器卷记得加入–privileged=true
在CentOS宿主机下新建目录/guoxiulong/redis
- 创建数据卷目录,将此目录作为挂载目录。
将一个redis.conf文件模板拷贝进/guoxiulong/redis目录下
/guoxiulong/redis目录下修改redis.conf文件
- 开启redis验证(可选)
requirepass xxxxxx
- 允许redis外部连接(必须)
- 注释掉# bind 127.0.0.1
- daemonize no
- 将daemonize yes注释起来或者daemonize no设置,因为该配置和docker run中-d参数冲突,冲突会导致容易一直启动失败。
- 开启redis持久化(可选)
appendonly yes
使用redis6.0.8镜像创建容器(也叫运行镜像)
命令:docker run -d -p 6379:6379 --name myredis --privileged=true -v /guoxiulong/redis/redis.conf:/etc/redis/redis.conf -v /guoxiulong/redis/data:/data redis:6.0.8 redis-server /etc/redis/redis.conf
成功运行:
测试redis-cli连接上来
请证明docker启动使用了我们自己指定的配置文件
修改配置文件前,可以访问16个默认数据库:
修改宿主机配置文件:(将默认数据库修改为10个)
测试redis-cli连接上来第2次
发现只能访问到十个数据库了:
8.5、安装nginx
见高级篇Portainer。