- Docker 基础概念

Docker托管到GitHub上:https://github.com/docker/docker-ce

>> Docker 安装

1、Linux-Ubuntu 安装 Docker / Windows 安装 Docker

2、Docker启动服务:systemctl start docker
若出错,删除/etc/docker/daemon.json:rm -f daemon.json

3、配置Docker加速镜像拉取;

4、安装Compose;


>> Docker 概念

~ 什么是容器技术

容器技术:是一种依托于Linux内核的虚拟化的技术;是操作系统级别的虚拟化;

容器是直接运行在操作系统内核之上的用户空间,所以容器虚拟化也称为“操作系统级虚拟化”,容器技术可以让多个独立的用户空间运行在同一台宿主机上;但是容器只能运行与宿主机相同或相似的操作系统,例如:Ubuntu服务器中只能运行RedHat Enterprise Linux,不能运行Windows;

Linux的内核特性:控件组(control group)、命名空间技术(namespace),使得容器与宿主机之间的隔离更加彻底,容器有独立的网络和存储栈,有自己的资源管理能力,这使得同一台宿主机上可以共存多个容器;

~ 什么是Docker

Docker就是装应用(网站、程序、系统)的一种容器;它可以将应用的代码打包,然后在服务器之间轻松的迁移;

  • 可以理解为:轻量级的虚拟机,把应用程序放在独立环境中运行;
  • 优点:快速的持续集成,服务的弹性伸缩,部署简单;节省机器资源;跨平台;
  • Docker设计的目的:是加强开发人员写代码的开发环境与应用程序部署的生产环境的一致性;
~ Docker容器化技术与虚拟机技术的区别

在这里插入图片描述
传统装软件:在硬件上安装操作系统,然后再操作系统上直接安装软件;
在这里插入图片描述
现在服务器server上不装操作系统,而是安装Hypervisor,然后将Hypervisor进行互连,这就表示这个互连的Hypervisor能使用下面所有的服务器资源(CPU、内存等);

互连的Hypervisor是一个虚拟化操作系统;

在虚拟化操作系统之上再安装操作系统,然后再操作系统上安装软件;这样就能使用这个整体的虚拟化操作系统来调度所有硬件的资源,分配给上面的各个虚拟操作系统;

在这里插入图片描述
在自己的电脑上安装虚拟机就是:硬件上安装宿主机(就是自己的操作系统),宿主机之上安装虚拟化技术(VMware),再在VMware上安装虚拟机(客户机Ubuntu),然后再安装软件;

使用Docker与VM的区别:
安装系统时,虚拟机必须要完整的虚拟出一块硬件资源(CPU、内存),占用的是底层服务器的资源,这部分资源是不能被共享的,然后再在硬件之上完整的创建一个操作系统;
而Docker直接使用宿主机的内核与资源,使用Docker创建的操作系统之间共享宿主机的内核与资源;

Eg:宿主机内存16G
使用VMware创建一个Ubuntu,分配2G内存,和一个CentOS,分配2G内存,那么宿主机只剩下12G内存可分配;
在Ubuntu上若需要使用3G的空间,就会出现内存溢出;
在CentOS上使用了1G的空间,那么就会有1G的空间浪费掉,其他的操作系统不能使用;

使用Docker不用给它分配任何资源,因为Docker使用的资源直接从宿主机获取;若在Docker上安装app1需要使用4G内存时,直接从宿主机拿来用就可以了;

DOcker可以有效利用宿主机的全部资源,虚拟机只能利用分配给它的部分资源;

Docker 优势:

  • 更高效的利用系统资源;
  • 更快速的启动时间;
  • 一致的运行环境;
  • 持续交付和部署;
  • 更轻松的迁移;
  • 更轻松的维护和扩展;
~ Docker容器的技术组件
  • 原生的Linux容器格式libcontainer (Docker容器的默认格式),或流行的容器品台lxc;
  • Linux内核的命名空间,用于隔离文件系统、进程、网络:
    • 文件系统隔离:每个容器都有自己的root文件系统;
    • 进程隔离:每个容器都运行在自己的进程环境中;
    • 网络隔离:容器间的虚拟网络接口和IP地址都是分开的;
    • 资源隔离和分组:使用cgroup将CPU和内存之类的资源独立分配给每个Docker容器;
  • 写时复制:文件系统都是通过写时复制创建的,这就意味着文件系统是分层的、快速的、而且占用的磁盘空间更小;
  • 日志:容器产生的STDOUT、STDERR、STDIN这些IO流都会被收集并记入日志,用来进行日志分析和故障排除;
  • 交互式shell:用户可以创建一个为tty终端,将其连接到STDIN,为容器提供一个交互式shell;
~ Docker思想

(1)集装箱思想:任何东西都可以装进集装箱,并且各种货物都被集装箱标准化了,集装箱与集装箱之间互不影响;
Docker使用集装箱的思想 将程序和依赖一起打包,程序放到哪里都不会缺东西,不用每次都配置环境;

(2)标准化思想

  • 运输方式标准化:将程序部署到仓库,其他电脑使用时直接从仓库拉取;(使用简单的命令即可完成操作)
  • 存储方式标准化:从存储仓库拉取程序时,不需要关心程序存在电脑中的什么位置,要运行、停止程序只需要执行简单的命令即可;
  • API接口标准化:使用docker提供的命令执行所有的应用;(eg:启动Tomcat服务器和启动其他服务器的命令不一样,但是使用docker 就可以使用统一的命令完成)

(3)隔离的思想:docker比虚拟机轻量,可以快速的创建、销毁;各个程序之间互不干扰;

  • 1、不同的应用程序可能会有不同的应用环境,比如Java开发的软件和Python开发的网站依赖的软件就不一样,若把它们依赖的软件都安装在一个服务器上可能会发生冲突,比如访问端口冲突;这时候就要隔离开发的两个网站;可以在服务器上创建不同的虚拟机,在不同的虚拟机上放置不同的应用,但是虚拟机的开销比较高;docker可以实现虚拟机隔离应用的环境的功能,并且开销比虚拟机小;

  • 2、若开发软件的时候用的是Ubuntu,但是运维管理的都是centos,运维在把你的软件从开发环境转移到生产环境的时候就会遇到一些Ubuntu转centos的问题,比如:有个特殊版本的数据库,只有Ubuntu支持,centos不支持,在转移的过程当中运维就得想办法解决这样的问题。这时候要是有docker你就可以把开发环境直接封装转移给运维,运维直接部署你给他的docker就可以了,而且部署速度快

  • 3、在服务器负载方面,如果你单独开一个虚拟机,那么虚拟机会占用空闲内存的,docker部署的话,这些内存就会利用起来;

~ Docker能做什么

Docker的应用场景:

  • 加速本地开发和构建流程,使其更加高效、更加轻量化;开发可以构建、运行、分享Docker容器,容器可以在开发环境中构建,然后提交到测试环境、生产环境;
  • 能够让独立的服务或应用程序在不同的环境中,得到相同的运行结果;
  • 可以用来创建隔离的环境来进行测试;
~ Docker解决什么问题

一个Javaweb程序的执行需要依赖:最底层的操作系统、系统上的JDK、Tomcat、代码、配置文件;

  • 操作系统变了,可能导致程序无法运行,比如程序调用了某些系统命令,换了一个操作系统,就调用失败;
  • JDK版本改变,导致程序无法运行,比如class文件使用JDK1.7编译,电脑上安装的是JDK1.6,就会发生class版本识别不了;
  • Tomcat:旧版本的配置在新版本中不支持;
  • 代码引用了电脑D盘某一个文件,换了一个电脑就找不到文件路径;
  • 配置文件少了,或者配置是和系统相关的,换了个系统就会出错;

Docker将操作系统、JDK、Tomcat、代码、配置文件,都装在集装箱里,打包部署到服务器上,在本机上怎么运行,在服务器上就怎么运行;

1、Docker解决了运行环境不一致带来的问题;
2、服务器上同时运行多个程序,一个程序挂了,可能导致其他程序无法正常运行,docker的隔离性解决了这一个问题;
把程序都放在docker里面运行,docker会在启动时给每一个程序限定最大使用的CPU内存硬盘,某一个程序发生死循环,挂的只有它自己,其他程序不受影响;


>> Docker 体系结构、核心技术:镜像/仓库/容器

在这里插入图片描述

~ Docker 架构模式

Docker 使用客户端-服务器 (C/S) 架构模式,通过在客户端(一个命令行工具)使用远程API(一整套RESTFul API)向服务器(Daemon)发出请求来管理和创建Docker容器,Daemon将完成所有工作并返回结果给客户端;

可以在同一台宿主机上运行守护进程和客户端,也可以从本地的Docker客户端 连接到 运行在另一台宿主机上的远程Docker守护进程;

docker build:构建镜像,然后上传到Docker仓库上,使用镜像的时候再由目的地从仓库上拉取镜像;

docker pull:客户端发送docker pull命令到docker daemon(守护进程),告诉daemon要拉取某个镜像,docker daemon现在本机查找镜像是否存在,若存在,并且是所需要的版本,就不会做任何操作,否则就会到docker的仓库里面查找所需要的镜像名字,找到了就会从docker仓库拉取到本地;

docker run:将命令从本机发送到本机的docker daemon,docker daemon检查镜像是否在本机已经存在,若不存在,就相当于执行了一个docker pull的操作从仓库拉取到本机,然后把镜像通过一定的方式运行起来,变成docker的容器;

Docker运行一个程序的过程就是:去仓库 把镜像 拉取到本地,然后用命令将镜像运行起来,变成容器;
Docker 容器通过 Docker 镜像来创建,镜像与容器的关系类似于面向对象中类与对象的关系;

~ Docker 仓库

docker镜像中心:https://hub.docker.com/explore/
网易蜂巢镜像中心:https://c.163yun.com/hub#/m/home/

  • 镜像保存在仓库中,而仓库存在于Registry中,默认的Registry是由Docker公司运营的公共的Registry服务,即Docker hub

  • 每个镜像仓库都可以存放多个镜像,可以使用docker pull命令来拉取某镜像仓库中的所有内容(以标签名tag来区分的所有镜像);使用docker images来列出本地的所有镜像;

  • 可以在创建容器的时候,通过在仓库名后面加上一个冒号和标签名来指定该仓库中的某一镜像:
    docker run -t -i --name containerName ubuntu:12.04 /bin/bash
    构建容器时最好指定仓库的标签,以便可以准确的指定容器的来源;不同标签创建出的容器会有所不同;

  • Docker Hub中有两种类型的仓库:

    • 用户仓库user repository:由Docker社区中的用户创建提供的,这些镜像没有经过Docker公司的确认和验证,so使用有风险;
      用户仓库命名:用户名/仓库名;
    • 顶层仓库top-level repository:由Docker内部人员来管理;由Docker公司和由选定的能提供优质的基础镜像的厂商管理(eg:Fedora镜像)
      顶层仓库命名:只有仓库名;
~ Docker 镜像与容器 image/container
  • 镜像本质上就是一系列文件;可以包括应用程序的文件,也可包括运行环境的文件;

  • 容器本质上就是一个进程,类似虚拟机,具有隔离性;
    可以想象成一个虚拟机,每个虚拟机都有自己的文件系统;可以把下图整个部分看成是一个容器的文件系统,也就相当于一个虚拟机里面的所有文件系统,容器与虚拟机的区别是,容器里面的文件系统是分层的,并且除了第一层是可读可写的,下面各层都是只读的;
    一个程序运行时需要写一些日志、文件,或者对系统的某些文件进行修改,所以容器在第一层创建了一个可读可写的文件系统;如果程序运行时要写一个镜像中的一个文件,需要将镜像文件拷到容器的最上层,然后再进行修改;修改之后,当应用读一个文件的时候,会从顶层开始查找,没找到才会找下一层;
    由于第一层的容器可以修改,而下层的镜像不可以修改,所以一个镜像可以生成多个容器独立运行,互不干扰影响;

  • 镜像是Docker生命周期中的构建或打包阶段,容器是启动或执行阶段;

  • 本地镜像都保存在Docker宿主机的/var/lib/docker目录下,每个镜像都保存在Docker所采用的存储驱动目录下面,如aufs/devicemapper
    所有容器都保存在/var/lib/docker/containers目录下;

  • Linux存储技术:联合文件系统UnionFS,是一种分层的文件系统,可以将不同的目录挂到同一个虚拟文件系统下;
    联合文件系统可以在同一个文件夹下看到其他两个文件夹里面的内容,通过这种方式,联合文件系统就可以实现文件系统的分层;Docker镜像就是利用这种分层的概念来实现的镜像的存储;
    联合加载指的是一次同时加载多个文件系统,但是在外面看起来只能看到一个文件系统;联合加载会将各层文件系统叠加到一起,这样最终的文件系统会包含所有底层的文件和目录;

  • 容器的文件系统:
    这里写图片描述

  • Docker镜像是由文件系统叠加而成的;

    • 最低层是一个操作系统的引导:引导文件系统bootfs,用户几乎不会和bootfs有什么交互,当一个容器启动后,它将会被移到内存中,而bootfs则会被卸载;
    • 第二层是一个具体的操作系统:root文件系统rootfs,位于bootfs之上;rootfs可以是一种或多种操作系统(Debian、Ubuntu);rootfs永远是只读状态;
    • 第三层是一些相关的软件的镜像:Tomcat、JDK;
    • 第四层存放应用代码;
  • 底下四层是镜像层都是只读的,只有最上面容器层是可读可写的;

  • 每一层都加载完成之后,这些文件都会被看做是同一个目录;相当于只有一个文件系统;

  • Docker将这些底层文件系统称为**镜像;(指的是单个文件系统,不是经过联合加载技术形成的一整个文件系统,即位于bootfs之上的各个rootfs) 最底部的镜像称为基础镜像**(base image),它是所有上面其他镜像的父镜像

  • 当从一个镜像启动一个容器时,Docker会构建出一个镜像栈,并且在该镜像栈的最顶层加载一个读写文件系统(读写层),这个读写层再加上其下面的镜像层,以及一些基础配置数据,就构成了一个容器在Docker中运行的程序就是在这个读写层中执行的

  • 当Docker第一次启动一个容器时,初始的读写层是空的,当文件系统发生变化时,这些变化都会应用到这一层上;Eg:若要修改一个文件,这个文件首先会从读写层下面的只读层复制到该读写层,该文件的只读版本依然存在,但是已经被读写层中的该文件副本所隐藏,这种机制称为 “写时复制(copy on write)”

  • 容器都是可以修改的,都有自己的状态,并且是可以启动和停止的;容器的这种特点,加上镜像分层框架,使得我们可以快速构建镜像并运行包含我们自己的应用程序和服务的容器;

  • 镜像可以有相同的镜像ID,但是标签名不同;

  • Docker在文件系统内创建镜像,使用这个镜像开启一个容器,该容器拥有自己的网络IP地址、以及一个用来和宿主机进行通信的桥接网络接口

~ Docker 虚悬镜像

使用docker images命令查看镜像时会看到有些镜像镜像名和标签都是<none>,这些镜像就是虚悬镜像;

这个镜像原本是有镜像名和标签的,原来为 mongo:3.2,随着官方镜像维护,发布了新版本后,重新 docker pull mongo:3.2 时,mongo:3.2 这个镜像名被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消,从而成为了 。除了 docker pull 可能导致这种情况,docker build 也同样可以导致这种现象。由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 的镜像。这类无标签镜像也被称为 虚悬镜像(dangling image) ;

可以用下面的命令专门显示这类镜像:$ docker image ls -f dangling=true
删除虚悬镜像:$ docker image prune


>> Docker守护进程 (引擎)

安装完Docker之后,需要确认守护进程是否运行;Docker以root权限运行它的守护进程,来处理普通用户无法完成的操作(如挂载文件系统);docker程序是Docker守护进程的客户端,同样也需要以root身份运行;

Docker安装完成后默认会立即启动守护进程,守护进程监听/var/run/docker.sock这个套接字文件,来获取来自客户端的Docker请求;若系统中存在名为docker的用户组,Docker就会将该套接字的所有者设置为该用户组,这样docker用户组的所有用户都可以直接运行Docker,而不需要再使用sudo命令了;

单个用户需要使用sudo命令,用户组用的不需要使用sudo命令,这方便了docker用户组对Docker的使用,但是存在安全隐患:docker用户组对Docker具有与root用户相同的权限;所以用户组中应该只添加确实需要使用Docker的用户和程序;

~ 配置Docker守护进程
  • 运行Docker守护进程时,可以使用-H标志指定不同的网络接口端口配置,例如:
    sudo /usr/bin/docker -d -H tcp://0.0.0.0:2375,将Docker守护进程绑定到宿主机上的所有网络接口;Docker不会自动检测到网络的变化,我们需要通过-H选项来指定服务器的地址:例如,把守护进程的端口改成4200,那么运行客户端时就必须指定docker -H :4200;若不想每次运行客户端时都加上-H标志,可以设置环境变量DOCKER_HOSTexport DOCKER_HOST=“tcp://0.0.0.0:2375”

  • 也可以通过-H标志指定一个Unix套接字路径sudo /usr/bin/docker -d -H unix://home/docker/docker.sock

  • 也可以同时绑定多个地址sudo /usr/bin/docker -d -H tcp://0.0.0.0:2375 -H unix://home/docker/docker.sock

  • 也可以通过在命令前指定DEBUG=1参数来输出更详细的信息;在使用Upstart的Ubuntu系统下,Docker守护进程生成的日志输出都保存在/var/log/upstart/docker.log文件中:DEBUG=1 /usr/bin/docker -d

  • 要想这些改动永久生效,需要编辑Docker启动配置文件:/etc/default/docker文件,此文件用来设置Docker启动时运行的各种选项;修改Docker守护进程启动时的启动选项:DOCKER_OPTS变量

~ 检查守护进程是否正在运行

在Ubuntu中,若Docker是通过软件包安装的话,可以运行Upstart的status命令来检查Docker守护进程是否正在运行:sudo status docker;也可以使用sudo start/restart/stop docker来启动/重启/停止Docker守护进程;

但是使用这些命令会报错:status: Unable to connect to Upstart: Failed to connect to socket /com/ubuntu/upstart: Connection refused

是因为:The error message means your Ubuntu is not using Upstart.
From Ubuntu 15.04, systemd is now the default init process instead of Upstart, and as a result some commands have changed.
With systemd, you can instead check the status of, for example, docker with the command:sudo service docker start/stop/restart/status


>> 镜像构建上下文

执行docker build -t imageName .命令最后面有个.,表示当前目录,是在指定构建镜像上下文路径;

  • Docker build的工作原理
    Docker 在运行时分为 Docker 引擎(服务端守护进程)和客户端工具;Docker 的引擎提供了一组 REST API,而如 docker 命令这样的客户端工具,则是通过这组 API 与 Docker 引擎交互,从而完成各种功能;因此,虽然表面上我们好像是在本机执行各种 docker 功能,但实际上,一切都是使用的远程调用形式在服务端(Docker 引擎)完成;也因为这种 C/S 设计,让我们操作远程服务器的 Docker 引擎变得轻而易举;

在这里插入图片描述
在执行docker命令的时候,其实是在请求docker的服务端,docker服务端会将请求的处理结果返回给客户端;

在这里插入图片描述

当我们进行镜像构建的时候,并非所有指令都会通过RUN指令完成,经常会将一些本地文件复制进镜像,比如COPYADD指令等;而docker build命令在构建镜像时,并非在本地进行构建操作,而是将构建的命令发送给服务端,由服务端接收指令完成镜像的构建操作;

构建的时候,用户会通过.指定构建镜像的上下文,docker build命令得知这个路径后,会将该路径下的所有内容打包,然后将压缩包同build指令一起发送给服务端,服务端收到构建的build指令和上下文压缩包后,会解压缩,从而获得构建镜像所需要的一切文件,然后根据指令,结合解压缩的文件,完成镜像的构建工作;

Dockerfile中的COPY ./package.json /app/指令,并不是要复制docker build命令所在的目录下的package.json文件,也不是复制DOckerfile所在目录下的package.json文件,它不复制在复制宿主机下的任何文件,而是复制上下文目录下的package.json文件;

这个上下文目录指的是复制随build指令一起上传到服务端的压缩文件解压后的文件目录;

COPY 这类指令中的源文件的路径都是相对路径,相对于构建上下文的路径;

COPY ../package.json /app/中,..指的是服务端存放解压缩文件的上级目录,是服务端的目录,有什么谁也不知道;

>> Docker网络三种模式

Linux利用namespace(命名空间)进行资源的隔离,Eg:PIDnamespace隔离进程,network namespace隔离网络;每个network namespace都提供一个独立的网络环境(网卡、路由等);

  • docker容器默认情况下会分配一个独立的network namespace,也就是网络类型中的bridge(桥接)模式;

  • 若启动容器时指定Host模式,那么容器将不会获得一个独立的network namespace,而是和主机共同使用一个,这个时候容器将不会再虚拟出自己的网卡,配置自己的IP等,而是会使用宿主机上的端口,也就是说在docker上使用网络 和在主机上使用网络是一样的;

  • 还有一种网络类型:None,没有网络;这种情况docker将不会跟外界的任何东西进行通讯;

使用bridge模式时涉及到一个问题:它使用的网络有独立的namespace,那么就需要一种技术:端口映射,使容器上的端口可以在主机上访问到;

docker可以指定把容器内的某一个端口,和容器主机上的某一个端口之间做一个映射,当访问主机上的这个端口的时候,就是访问容器里面的那个端口;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值