Docker学习

1、什么是docker?

项目部署的问题:

首先我们得了解下项目部署的问题,运行环境也较为复杂,部署时会碰到一些问题。

  • 依赖关系复杂,容易出现兼容性问题
  • 开发、测试、生产环境有差异

image.png
前端要依赖nodejs、后端的redis、数据库以及微服务要用的的异步通信MQ,等等,这些应用都需要部署到我们的服务器上,而大多数服务器都采用Linux操作系统,它们还需要很多依赖和库,但是每一个应用所需要的函数库和依赖很可能很不一样,可能一样但是版本不同,就像这种依赖关系就很容易产生兼容性问题。你废了老半天劲终于把开发环境给弄好了,但是还有测试环境,生产环境还没配置,最可怕的是这些Linux操作系统可能不同,你在这个环境下配好的各种东西在其他操作系统中能运行嘛?

Docker

Docker如何解决依赖的兼容问题的?
image.png

  • 将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包
  • 将每个应用放到一个隔离容器中去运行,避免互相干扰

但是需要注意的是这只是解决了混乱依赖的问题,但是仅限于一个操作系统。
在打包的时候,是基于某种操作系统进行打包的,比如一个项目是基于ubantu版本的,那么这个版本和依赖也是基于ubantu版本的,那docker怎么跨系统运行呢?

Docker跨系统运行

所有的linux操作系统都可以分为两层,一层是Linux内核,一层是上层的系统应用,内核负责与计算机硬件进行交互。
image.png
内核与硬件进行交互,提供操作硬件的指令,如果你要基于这些指令去开发应用,那可就太麻烦了,所以说就有了系统应用,就比如说ubantu,它会将内核的指令组装再封装形成一个内核函数,许多函数在一起形成了函数库,程序调用函数库,函数库调用内核指令,指令调用底层的硬件,从而实现程序的执行。
那么问题来了,一个ubantu的应用为什么不能在centos上运行呢?
image.png
ubantu和CentOS都是基于Linux内核,只是系统应用不同,提供的函数库有差异,可能在ubantu上有的函数在centos上没有
既然每个应用都依赖于系统函数库,那么我将其系统函数库一起打包就行了
Docker如何解决不同系统环境的问题?

  • Docker将用户程序与所需调用的系统(比如Ubantu)函数库一起打包
  • Docker运行到不同操作系统时,直接基于打包的库函数,借助操作系统的Linux内核来运行。
总结

Docker如何解决大型项目依赖关系复杂,不同组件依赖的兼容性问题?

  • Docker允许开发中将应用、依赖、函数库、配置一起打包,形成可移植的镜像
  • Docker应用运行在容器中,使用沙箱计机制,相互隔离

Docker如何解决开发、测试、生产环境有差异的问题?

  • Docker镜像中包含完整的运行环境,包括系统函数库,仅依赖系统的Linux内核因此可以在任意Linux操作系统上运行。

Docker是一个快速交付应用、运行应用的技术:

  • 可以将程序及其依赖、运行环境一起打包为一个镜像,可以迁移到任意Linux操作系统
  • 运行时利用沙箱机制形成隔离容器,各个应用互不干扰
  • 启动、移除都以通过一行命令完成,方便快捷

2、Docker与虚拟机之间的区别

image.pngimage.png
image.png
虚拟机是在操作系统中模拟硬件设备,然后运行另一个操作系统,比如在Windows系统里面运行Ubantu系统,这样就可以运行人意的ubantu应用了。

  • docker是一个系统进程;虚拟机是在操作系统中的操作系统
  • docker体积小、启动速度快、性能好;虚拟机体积大、启动速度慢、性能一般

3、初识Docker

**镜像:**Docker将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起,称为镜像。
image.png
就比如说mysql镜像,mysql需要各种各样所需要的依赖,这些依赖最终落地到硬盘就是一个一个的文件,比如说这里有Mysql运行时所需要的Data目录文件,日志logs文件、bin里边的可执行文件等等,这些就组成了Mysql本身,也就是说:镜像就是应用中的文件
容器:镜像中的应用程序运行后形成的进程就是容器,只是Docker会给容器做隔离,对外不可见。
image.png
容器可以看作成这样一个小盒子,这个小盒子将来会利用Linux的手段,给它形成隔离空间,里面会有自己独立的CPU资源、内存资源,甚至还会有独立的文件系统,那么在这个容器内运行着的这个进程就会以为自己是这个系统内的唯一进程,从而起到一个隔离的效果。
image.png
启动多个容器,它们之间也都是互相隔离的。
那么它们能不能把自己的数据写进镜像呢?
答:不可以,因为这样会对镜像产生一个污染,人家这个镜像干干净净的,给你一顿咔咔乱写,万一你写进的东西造成了一些错误导致这个镜像不可用了那怎么办?
所以说镜像是
只读不写

那么问题又来了,容器往哪里写数据呢?
image.png
很简单就是各自拷贝一份文件到自己的容器当中
那么问题又来了,如何把镜像共享给别人去使用呢?给同事,或是给网络当中的其他程序猿?

Docker和DockerHub
  • DockerHub:DockerHub是一个Docker镜像托管平台。这样的平台称为Docker Registry。

image.png
那么我们程序猿呢就可以利用Docker提供的一些命令去完成镜像的构建
image.png
然后就可以上传到DockerHub这样的服务器上去
image.png
那么问题又来了,我们如何利用docker进行镜像的构建,或者说从远端拉取镜像呢?又该怎样去运行容器呢?
Docker架构:
Docker是一个CS架构的程序,由两部分组成:

  • 服务端(server): Docker守护进程,负责处理Docker指令,管理镜像、容器等。
  • 客户端(client): 通过命令(本地)或RestAPI(远程)向Docker服务端发送指令。可以在本地或远程向服务端发送指令。

就比如,客户端发出一个docker build命令,发送出去后会被docker daemon守护进程接受和处理,那么它会利用你所提供的哪些数据构建成一个镜像。
image.png
除了这种方法可以获取镜像外,另外还有一种方法,就是从Registry拉取镜像,因为Registry里边会有各种官方提供的优质镜像。可以使用docker pull命令,docker daemon守护进程收到命令后会从Registry拉取镜像。
image.png
那么下边就开始运行镜像、创建容器了,这个时候就是使用**docker run,**告诉server要开始创建容器了,而守护进程就会帮助你完成容器的创建,然后完成部署就可以了。

总结

镜像:

  • 将应用程序及其依赖、环境、配置打包在一起

容器:

  • 镜像运行起来就是容器,一个镜像可以运行多个容器

Docker结构:

  • 服务端:接受命令或远程请求,操作镜像或容器
  • 客户端:发送命令或者请求到Docker服务端

DockerHub:

  • 一个镜像托管的服务器,类似的还有阿里云镜像服务,统称为DockerRegistry

4、Docker基本操作

镜像相关命令
  • 镜像名称一般分两个部分组成:[repository]:[tag]

image.png

  • 如果没有指定tag,默认就是latest,代表最新版本的镜像
  • 获取镜像应该怎么获取呢?一般有两种做法,第一种呢就是从本地获取,你需要一个Dockerfile的本地文件,然后利用一个docker build命令把它构建成一个镜像;除了从本地构建镜像外,大多数情况下会从Docker Rejistry镜像服务器去拉取镜像,会用到docker pull命令;已经获取到镜像了,那么我想知道我本地有哪些镜像,应该怎么办呢?可以使用docker images命令去查看镜像,删除镜像使用docker rmi;那么我想把镜像分享给别人怎么办,这时有两种方法,第一种使用docker push推送镜像到镜像服务器;第二种方式就是用U盘copy给你的同事,可以使用一个docker save,这个命令会把镜像保存为一个压缩包,copy过去之后又怎么把它变成镜像呢?可以使用docker load命令将其加载为镜像。

image.png

容器相关命令

比较常见的命令就是docker run了,这个命令不仅仅可以创建容器,还可以使这个容器处于一个运行状态;容器除了运行状态,还有暂停,停止状态,只需要使用简单的几个命令,就可以实现这几个命令之间的切换了,比如说我想要容器从运行进入暂停状态,可以使用docker pause命令,相反,如果你想要其从暂停恢复运行,则可以使用docker unpause,参考这个,停止是docker stop,从停止到运行使用docker start;可以使用docker ps查看所有运行的容器及状态,可以使用docker logs查看容器运行日志,当然如果你不满足于表面观察容器,你想深入内部了解下,可以使用docker exec,这个命令可以使你进入容器内部做你想做的事情,都被你玩明白了,如果你不想要这个容器了你应该怎么办?使用docker rm 删除指定容器。
image.png

运行一个容器

**步骤一:**去docker hub查看Nginx的容器运行命令

docker run -name containerNamer -p 80:80 -d nginx
命令解读:
  • docker run:创建并运行一个容器
  • –name:给容器起一个名字,比如叫做mn,这样的话你将来查找容器,管理容器就很方便了,所以每一个容器都要有一个唯一的名称
  • -p:将宿主机端口与容器端口映射,冒号左侧是宿主机端口,右侧是容器端口

将宿主机端口与容器端口映射这个是什么意思呢?比方说我这里有一台centos的服务器,这台服务器的ip地址是192.168.150.101,现在我们在服务器上部署了一台Nginx容器,它的端口是80,那么我们用户想要来访问容器,能不能进行访问?那是必然不能的,因为**容器是对外隔离的,也就是说任何请求想要来访问我的容器,滚,不让你来,那怎么办啊。你创建容器的目的不就是让别人访问嘛,你这还隔离了不让别人访问?那怎么行呢?所以要做一个端口映射,宿主机有自己的端口,任何进入宿主机80的这个请求都会转发给容器的80端口去执行,这就等于用户访问了容器了,说简单点端口映射的作用就是:**让原本隔离的容器暴露一个小口,让你透过它来访问,如果没有它,任何人都无法访问容器。
image.png

  • -d: 代表后台运行,如果不加这个-d那就是前台运行,什么是前台运行呢?就像PPT一样,如果你点击❎号,那么不好意思,它就直接关掉了,那这个程序就结束了;那什么叫做后台运行呢?就像360的那个杀毒软件,你点击❎号,它关闭了嘛?没有,它还在运行着呢,这就是后台运行
  • nginx:镜像名称,例如nginx

这条命令整体解释一下就是我基于最新版本的nginx,创建一个容器,然后给它起一个名字,给它做一个80端口的映射,让它保持后台持续运行。

进入容器,修改文件

**步骤一:**进入容器。进入我们刚刚创建的nginx容器的命令为:

docker exec -it mnginx bash

命令解读:

  • docker exec: 进入容器内部,执行一个命令
  • it: 给当前进入的容器创建一个标准输入、输出终端,允许我们与容器交互
  • mn: 要进入的容器的名称
  • bash:进入容器后执行的命令,bash是一个linux终端交互命令

**步骤二:**进入nginx的HTML所在目录 /usr/share/nginx/html

cd /usr/share/nginx/html

**步骤三:**修改index.html的内容

sed -i 's#Welcome to nginx#你好 wql#g' index.html
sed -i 's#<head>#</head><meta charset="utf-8">#g' index.html

5、数据卷

容器与数据耦合的问题:

  • 不便于修改:当我们要修改Nginx的html内容时,需要进入容器内部修改,很不方便。
  • **数据不可服用:**在容器内的修改对外是不可见的。所有修改对新创建的容器是不可复用的。
  • **升级维护困难:**数据在容器内,如果要升级容器必然删除旧容器,所有数据都要跟着删除了。
数据卷概念

是一个虚拟目录,指向宿主机文件系统中的某个目录。
比如说一个有Docker的主机,那么在这个主机中就会由docker去管理很多很多的数据卷,而所有的数据卷一定会指向宿主机文件系统中的某一个目录,那么这个目录是谁呢,这个目录就是**/var/lib/docker/volumes**,比如说我现在利用docker创建了一个新的数据卷,这个数据卷的名称叫做html,那么我们的docker就会在指定的宿主机文件系统的指定目录下再创建一个/html的目录;又比如说我又创建了一个conf文件夹,那么它同样会在volumes文件夹下创建一个conf文件夹;然后每一个数据卷都跟真实的目录呢进行一个映射,所以呢可以认为数据卷是一个虚拟的,不是真实存在的,只是一个概念,而真正指向的是硬盘上的真实文件夹。
而容器在创建之后就可以使用这个数据卷,就比如说我们有一个nginx容器,我们知道它的静态资源在/usr/share/nginx/html目录下,我们可以让nginx内部目录与数据卷进行关联,而当它与数据卷进行关联时,它本质上是对宿主机文件系统上的目录进行关联,那么这个时候docker就会管理这个容器里,比方说往静态目录里写了点什么东西,那么这个时候会立即写进宿主机的文件系统里,而反过来,如果在宿主机的指定目录修改了文件,那么也会立即反映到容器里。
那么这个时候之前我们所说的几个问题就解决了,第一个问题就是修改不方便,就是你对宿主机指定目录下文件的任意修改,一定会立即反映到容器内部,再也不用到容器内部修改了。第二个就是数据共享的问题,假如说你对一个容器修改了很多很多配置,这时又要新增加一个新的容器,这个时候我们希望这个配置能够共享过来,那么这个时候怎么办呢?我们可以让第二个容器的conf目录也挂载同一个conf数据卷,所以原来容器对conf目录的修改在新的容器中也能看到。还有第三个问题就是数据的安全删除的问题,将来有一天你要升级版本,结果你不小心把容器给删了,但是没关系,因为你的数据卷还在这里,将来你如果有更新了新的容器新的版本,那么你依然可以挂载到这个数据卷上,这样就可以共享之前的数据。

操作数据卷

数据卷操作的基本语法如下:

docker volume [COMMAND]

docker volume命令是数据卷操作,根据命令后跟随的command来确定下一步的操作。

  • create 创建一个新的volume
  • inspect 显示一个或多个volume的信息
  • ls 列出所有的volume
  • prune 删除未使用的volume
  • rm 删除一个或多个指定的volume

总结:
数据卷的作用:

  • 将容器与数据分离,解耦合,方便操作容器内数据,保证数据安全

数据卷操作:

  • docker volume create 创建
  • docker volume ls 列出所有数据卷
  • docker volume inspect 查看数据卷的具体位置
  • docker volume rm 移除
  • docker volume prune 移除未使用的
挂载数据卷

如何将数据卷挂载到一个容器当中
我们在创建容器时,可以通过-v参数来挂载一个数据卷到某个容器目录
image.png
总结:
数据卷挂载方式:

  • -v volumnName: /targetContainerPath
  • 如果容器运行时volume不存在,会自动被创建出来
宿主机目录直接挂载到容器

目录挂载与数据卷挂载的语法是类似的:

  • -v[宿主机目录]:[容器内目录]
  • -v[宿主机文件]:[容器内文件]

对比:
image.png

6、Dockerfile自定义镜像

镜像结构
  • 镜像就是将应用程序及其所需要的系统函数库、环境、配置、依赖打包而成

    如果没有底层的系统函数库,你怎么完成环境的配置?如果没有环境变量你怎么去做依赖的安装呢?如果没有依赖安装,你怎么去完成应用安装,如果没有应用安装,你怎么去做应用的配置呢?可见,镜像不仅仅是把这些东西揉在一起,还要按照一定的顺序去分层构建。
    image.png
    先后顺序咱们能理解,依赖关系有先有后,但为什么要分层呢?我揉成一个疙瘩不行嘛?**这还真不行!!!**你想啊,现在你揉成一个疙瘩整了一个5.7的镜像,而后我们的系统升级了,又搞了一个5.8的镜像,那你不能在原基础上改了,因为这全混成一团了啊,那怎么办啊?你只能从头开始再构建了啊,麻烦不麻烦?但是我要是分层了那可就不一样了,整完基础分一层,整完环境我再分一层,整完配置再分一层… 直到后边构建5.7,安装,再安装5.8的时候,可能就是上边的几层不想要了,下边的几层我还想要,是不是可以基于它往上继续构建?
    总结:
    镜像是分层结构,每一层称为一个Layer

  • BaseImage层:包含基本的系统函数库、环境变量、文件系统

  • Entrypoint:入口,是镜像中应用启动的命令

  • 其他:在BaseImage基础上添加依赖、安装程序、完成整个应用的安装和配置

Dockerfile语法

什么是Dockerfile?
DockerFile就是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层Layer。
image.png

  • Dockerfile的本质是一个文件,通过指令描述镜像的构建过程
  • Dockerfile的第一行必须是FROM,从一个基础镜像来构建
  • 基础镜像可以是基本操作系统,如Ubuntu。也可以是其他人制作好了的镜像,例如:java:8-alpine
构建Java项目

docker build -t javaweb:2.0 . .代表当前目录

7、DockerCompose

DockerCompose概念
  • 什么是dockercompose:可以基于Compose文件帮助我们快速部署分布式应用,而无需手动一个个创建和运行容器!
  • Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。

回顾一下,之前呢我们是利用docker run命令来运行每个容器,而现在可以使用compose文件来定义集群中的n个容器如何运行,那是不是可以可以认为compose文件是n个docker run命令的一个集合呢?实际上恰好就是如此,只不过啊,它不是直接用run,它把我们run中的东西利用我们另外一种语法,也就是指令来代替了,那这个语法长什么样子呢?
image.png
总之,DockerCompose的作用就是帮助我们基于集群快速部署分布式应用,无需一个个微服务去构建镜像和部署。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值