部署方式演变

部署方式演变

  • 传统部署时代
    早期,企业直接将应用程序部署在物理机上。由于物理机上不能为应用程序定义资源使用边界,我们也就很难合理地分配计算资源。例如:如果多个应用程序运行在同一台物理机上,可能发生这样的情况:其中的一个应用程序消耗了大多数的计算资源,导致其他应用程序不能正常运行。应对此问题的一种解决办法是,将每一个应用程序运行在不同的物理机上。然而,这种做法无法大规模实施,因为资源利用率很低,且企业维护更多物理机的成本昂贵。
    传统部署时代

  • 虚拟化部署时代

    • 针对上述问题,虚拟化技术应运而生。用户可以在单台物理机的CPU上运行多个虚拟机(Virtual Machine)。
    • 虚拟化技术使得应用程序被虚拟机相互分隔开,限制了应用程序之间的非法访问,进而提供了一定程度的安全性。
    • 虚拟化技术提高了物理机的资源利用率,可以更容易地安装或更新应用程序,降低了硬件成本,因此可以更好地规模化实施。
    • 每一个虚拟机可以认为是被虚拟化的物理机之上的一台完整的机器,其中运行了一台机器的所有组件,包括虚拟机自身的操作系统。
      虚拟化部署时代

     

  • 容器化部署时代
    容器与虚拟机类似,但是降低了隔离层级,共享了操作系统。因此,容器可以认为是轻量级的。
    与虚拟机相似,每个容器拥有自己的文件系统、CPU、内存、进程空间等
    运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦
    容器化的应用程序可以跨云服务商、跨Linux操作系统发行版进行部署

容器化部署时代

什么是docker

  • Docker 是一个开源的应用容器引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在本地编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack 集群和其他的基础应用平台。

  • 简单的理解,Docker类似于集装箱,各式各样的货物,经过集装箱的标准化进行托管,而集装箱和集装箱之间没有影响。也就是说,Docker平台就是一个软件集装箱化平台,这就意味着我们自己可以构建应用程序,将其依赖关系一起打包到一个容器中,然后这容器就很容易运送到其他的机器上进行运行,而且非常易于装载、复制、移除,非常适合软件弹性架构。

docker跟虚拟机区别

Docker可以让一个应用在任何操作系统中非常方便的运行。而以前我们接触的虚拟机,也能在一个操作系统中,运行另外一个操作系统,保护系统中的任何应用。

两者有什么差异呢?

虚拟机(virtual machine)是在操作系统中模拟硬件设备,然后运行另一个操作系统,比如在 Windows 系统里面运行 Ubuntu 系统,这样就可以运行任意的Ubuntu应用了。

Docker仅仅是封装函数库,并没有模拟完整的操作系统,如图:

docker跟虚拟机区别1
由于容器所需的资源要少得多(例如,它们不需要一个完整的 OS),所以它们易于部署且可快速启动。这使你能够具有更高的密度,也就是说,这允许你在同一硬件单元上运行更多服务,从而降低了成本

对比
docker跟虚拟机区别2
 
docker跟虚拟机区别3  

docker 好处(节省项目环境部署时间)

  • 场景1:单项目打包

    • 每次部署项目到测试、生产等环境,都要部署一大堆依赖的软件、工具,而且部署期间出现问题几率很大,不经意就花费了很长时间。

    • Docker主要理念就是环境打包部署,可在任意Docker Engine运行。前期我们只需要将每个项目环境打包到镜像,push到镜像仓库,当有需要部署这个项目时,直接pull镜像启动容器,这个项目就可以访问了!一次构建多次部署,一劳永逸。

  • 场景二:环境一致性

    • 开发工程师在Windows系统上开发项目,测试、生产环境操作系统都是Linux系统,这就产生了环境不一致的情况:项目在开发电脑本地运行没问题,到了测试或生产环境就运行不起来,解决这问题最好方式就是这三处环境保持一致。软件版本、操作系统、物理机、云主机……试想下,能做到吗?

    • Docker将项目环境打包成镜像,可以在任何Docker Engine上浪。此时Docker就是我们这些项目的基石,Docker可移植性,保持运行状态一致性,可想而知,是否更容易解决问题呢?

  • 场景三:持续集成

    *一个项目版本快速迭代的测试场景,需要一个合理的CI(持续集成)/CD(持续部署)环境支撑。CI/CD是一个周期性自动化项目测试流程,包括构建、部署、测试、发布等工作,很少需要人工干预。

项目测试流程大致如下图:

图片/2022/08/21/Docker知/pasted-11.png

Docker结合Jenkins构建持续集成环境大致如下图:

图片/2022/08/21/Docker知/pasted-12.png
Docker在上面这个图的作用是项目镜像构建和快速部署,打通测试环境与生产环境,高度保持多个环境之间一致性。

  • 场景四:微服务
    • 微服务是近几年来IT圈内谈论比较多的一个名词,意义也很简单:尽可能细粒度拆分业务程序架构,由多个独立服务组成业务系统。

    • Docker的容器设计原则:一个容器一个服务,容器之间相互隔离,不妨试想一下,如果容器作为这些独立服务的部署单元,是不是有点恰到好处呢?

  • 场景五:弹性伸缩
    • 说到弹性伸缩,通常是集群模式下存在。像AWS AutoScaling,可以自定义资源阈值,SLB自动添加EC2云主机,应对业务访问量突发情况。

    • 当适用Docker技术以后,这种弹性伸缩的单元就是云主机之上的容器了。

    • 容器集群化管理已经有成熟的解决方案,比如:官方的Swarm,谷歌的K8S

    • 由于Docker容器快速启动特性,可以很快速的启动几十个、上百个容器来提供更多并发和资源利用率(如果宿主机资源不够,还需要加主机到集群中)。

docker 好处总结

根据上述应用场景总结下Docker特点:开箱即用,快速部署,可移植性强,环境隔离等。
简化部署流程,提高生产力!

mac安装docker

mac安装docker

docker安装nginx

  • run nginx

    1
    docker run -d --name nginx  -p 8081:80 ngin
  • 访问Nginx
    http://localhost:8081
    访问Nginx

  • 查看log

    1
    docker logs -f nginx

    查看log

  • 进入容器

    1
    docker exec -it nginx bash

    进入容器

  • 停止容器

    1
    docker stop nginx
  • 查看容器情况

1
docker ps -a

查看容器情况

  • 清理停止容器
    1
    docker container prune

清理停止容器

  • 新建目录 在某个目录新建html
    1
    mkdir html
  • 进入目录
    1
    cd html
  • 创建页面
    1
    echo 'welcome to nginx' > index.html
  • 运行命令
    把命令行xxx换成html目录下
    1
    docker run --name some-nginx -v /xxx/html:/usr/share/nginx/html -p 8081:80 -d nginx
  • 重新访问http://localhost:8081
    重新访问

运行 nginx的总结

docker核心:镜像,容器,仓库

docker 常用命令:

  • run— 运行一个镜像
  • images –查看本地镜像库
  • ps -a –查看本地所有容器状态
  • container prune –清理不正常容器
  • stop –停止容器
  • logs -f 容器id或容器名称 –查看日志
  • exec -it 容器id或容器名称 sh –进入容器
  • docker info–查看docker 信息

Docker daemon

  • docker采用C/S架构,Dcoker daemon作为服务端接受来自客户端请求,并处理这些请求,比如创建容器、管理镜像。
  • 为了兼容OCI标准,Docker1.1之后也做了架构调整,Docker容器运行已经不是简单的通过Docker daemon来启动,而是集成了containerd、runc等多个组件。

Docker daemon

  • Containerd:是一个简单的守护进程,管理shim,向Docker Engine提供接口。使用UnixSocket通信,协议是grpc。
  • Shim:管理一个容器
  • runC:运行一个容器。是基于OCI标准的一个容器技术实现,是一个可以直接创建和运行容器的工具。runc直接与容器所依赖的cgroups/kernel等进行交互,负责容器所需环境。

docker -镜像(image)

  • Docker的流行,很大因素是取决于有数十万计免费的应用镜像,使得用户或者开发者很容器找到可用的镜像。
  • 镜像不是一个单一的文件,而是有多层构成。可以理解为镜像是创建容器的模板,一个镜像可以创建N个容器。镜像通常封装了一个应用的基础环境。
  • Docker 镜像(Image),就相当于是一个 root 文件系统(不包含linux内核而有精简linux操作系统)

docker–容器(container)

  • Container中文意思是集装箱,很多人叫容器,其实延续了原理的Linux container,不管叫哪个,含义是一样的。我觉得叫容器比较合适。容器本质上是Linux系统上的一个进程,这个父进程可能会有多个子进程组成,这个一组进程受资源限制,与其他组进程之间隔离。这种运行时的状态成为容器。

  • 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

docker 镜像仓库(images Repository)

  • 容器是通过镜像创建的,大量的镜像需要找一个地方存放,这就需要Registry(注册中心)。
  • 企业通常自建私有仓库,也可以使用公共仓库,例如:
    • Docker Hub 地址:https://hub.docker.com
    • Docker官方提供的公共托管Registry,上面有很多现成的镜像,Docker CLI默认就是从这个仓库下载的。
    • VMware Harbor 地址:https://github.com/goharbor/harbor VMware Harbor(简称Harbor)项目是由VMware中国研发团队开发的开源容器镜像仓库系统

build java环境(dockerfile)

我们要运行一个spring boot web项目,我们就需要安装java,配置环境变量等等
现在我使用DockerFile 创建有java环境镜像

  • 设置阿里云镜像加速
    阿里云镜像加速
  • centos Dockerfile内容
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    FROM centos 
    LABEL Author="ywtana<xx@qq.com>"
    RUN sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* && \
    sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* && \
    yum -y update && \
    yum install -y java-11-openjdk tzdata && \
    yum clean packages && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo Asia/Shanghai > /etc/timezone && \
    rm -rf /tmp/* /var/cache/*
    RUN groupadd -r test && \
    useradd -g test -r test && \
    mkdir /test && \
    chown -R test:test /test
    USER test
    WORKDIR /test
    RUN ls -al /

    build命令
    1
    docker build -t openjdk11_centos .
    build成功后
    1
    docker images
    运行 test用户登录
    1
    docker run -u test:test -itd --name openjdk openjdk11_centos
    进入容器:
    1
    docker exec -it openjdk sh
    进入容器后输入
    1
    java version

java version

test目录

Dockfile描述

Dockfile描述

DockerFile 指令

DockerFile 指令1
DockerFile 指令2

docker 命令

上传docker镜像至阿里云

访问密码

  • 打开终端登录阿里云Docker Registry
    1
    sudo docker login --username=3586*****@163.com registry.cn-hangzhou.aliyuncs.com
  • docker tag
    1
    docker tag nginx  registry.cn-hangzhou.aliyuncs.com/test_peter/nginx:latest
  • docker push
    1
    docker push registry.cn-hangzhou.aliyuncs.com/test_peter/nginx:latest
  • docker pull
    1
    docker pull registry.cn-hangzhou.aliyuncs.com/test_peter/nginx:latest
    docker 命令

docker命令说明

docker 命令1

docker 命令2

docker run 参数说明

语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG…]

  • -d: 后台运行容器,并返回容器ID;
  • -i: 以交互模式运行容器,通常与 -t 同时使用;
  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口
  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
  • –name=”nginx-lb”: 为容器指定一个名称;
  • –dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
  • -h “mars”: 指定容器的hostname;
  • -e username=”ritchie”: 设置环境变量;
  • –env-file=[]: 从指定文件读入环境变量;
  • –cpuset=”0-2” or –cpuset=”0,1,2”: 绑定容器到指定CPU运行;
  • -m :设置容器使用内存最大值;
  • –net=”bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
  • –volume , -v: 绑定一个卷

docker 镜像与容器联系和存储驱动

  • Docker镜像是由多个只读层添加而成,启动容器时,Docker加载值读镜像层并在镜像栈顶部添加一个读写层。
  • 如果运行中的容器修改了现有的一个已经存在的文件,那么该文件将会在读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写曾中该文件的副本所隐层,这就是我们所说的写时复制,Elasticsearch也是用了写时复制。和这个略有不同。
  • 默认情况下,容器不使用任何 volume,此时,容器的数据被保存在容器之内,它只在容器的生命周期内存在,关闭并重启容器,其数据不会受到影响,但是删除Docker容器,数据将会全部丢失。当然,也可以使用 docker commit 命令将它持久化为一个新的镜像
  • Docker的数据持久化即使数据不随着container的结束而结束,数据存在于host机器上——要么存在于host的某个指定目录中(使用bind mount),要么使用docker自己管理的volume(/var/lib/docker/volumes下)
  • docker run 指定 -v参数
  • bind mount例如:
    1
    docker run --name some-nginx -v /root/html:/usr/share/nginx/html -p 8081:80 -d nginx
  • 使用docker volume create my-volume-2 后
    1
    docker run --name some-nginx -v my-volume-2:/usr/share/nginx/html -p 8081:80 -d nginx

docker网络

  • Docker自身的4种网络工作方式,和一些自定义网络模式
    安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host

    • host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
    • Container:创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。
      None:该模式关闭了容器的网络功能。
    • Bridge:此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。
  • 使用docker network ls 命令列出这些网络

docker network ls

  • run创建Docker容器时
    • host模式:使用 –net=host 指定。
    • none模式:使用 –net=none 指定。
    • bridge模式:使用 –net=bridge 指定,默认设置。
    • container模式:使用 –net=container:NAME_or_ID 指定。

docker 原理

docker 原理

  • 命名空间(namespaces)是 Linux 为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法。

  • CGroups:让系统中所运行任务(进程)的用户定义组分配资源—比如CPU时间、系统内存、网络带宽

  • UnionFS:把文件系统上多个目录(分支)内容联合挂载到同一个目录下

namespace

命名空间(namespaces)是 Linux 为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法。在日常使用 Linux 或者 macOS 时,我们并没有运行多个完全分离的服务器的需要,但是如果我们在服务器上启动了多个服务,这些服务其实会相互影响的,每一个服务都能看到其他服务的进程,也可以访问宿主机器上的任意文件,这是很多时候我们都不愿意看到的,我们更希望运行在同一台机器上的不同服务能做到完全隔离,就像运行在多台不同的机器上一样。

namespace

CGroups

我们通过 Linux 的命名空间为新创建的进程隔离了文件系统、网络并与宿主机器之间的进程相互隔离,但是命名空间并不能够为我们提供物理资源上的隔离,比如 CPU 或者内存,如果在同一台机器上运行了多个对彼此以及宿主机器一无所知的『容器』,这些容器却共同占用了宿主机器的物理资源。

CGroups

UnionFS

Linux 的命名空间和控制组分别解决了不同资源隔离的问题,前者解决了进程、网络以及文件系统的隔离,后者实现了 CPU、内存等资源的隔离,但是在 Docker 中还有另一个非常重要的问题需要解决 - 也就是镜像。
UnionFS

docker 常用镜像

docker mysql

  • 运行mysql 并映射本地数据文件夹 ,映射容器服务的 3306 端口到宿主机的 3306 端口。外部可以直接通过宿主机ip:3306 访问到 的服务;–restart=always参数能够使我们在重启docker时,自动启动相关容器
    1
    docker run --name mysql --restart=always -p 3306:3306 -v /Users/tanyanwen/Downloads/html/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
  • 命令进入mysql容器
    1
    docker exec -it mysql /bin/bash
  • 输入mysql命令 登录mysql
    1
    mysql -uroot -p
    mysql命令

docker redis

  • 运行redis 镜像 并映射容器服务的 6379 端口到宿主机的 6379 端口。外部可以直接通过宿主机ip:6379 访问到 Redis 的服务;–restart=always参数能够使我们在重启docker时,自动启动相关容器
    1
    docker run -itd --restart=always --name redis -p 6379:6379 redis

ubuntu build openjdk11环境

  • Dockfile
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    FROM ubuntu 
    LABEL Author="peter<xx@qq.com>"
    RUN apt update -y && \
    apt upgrade -y && \
    apt install -y openjdk-11-jre-headless tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo Asia/Shanghai > /etc/timezone && \
    rm -rf /tmp/* /var/cache/*
    RUN groupadd -r test && \
    useradd -g test -r test && \
    mkdir /test && \
    chown -R test:test /test
    USER test
    WORKDIR /test
    RUN ls -al /
  • 执行build命令
    1
    docker build -t openjdk11_ubuntu .
  • 运行
    1
    docker run -u test:test -it --name openjdk openjdk11_ubuntu
  • 查看java
    1
    java -version
    java -version

alpine build openjdk11环境

  • Dockfile
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    FROM alpine 
    LABEL Author="peter<xx@qq.com>"
    RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
    apk update && \
    apk upgrade && \
    apk add openjdk11 tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo Asia/Shanghai > /etc/timezone && \
    rm -rf /tmp/* /var/cache/apk/*
    RUN addgroup test && \
    adduser -G test test -D && \
    mkdir /test && \
    chown -R test:test /test
    USER test
    WORKDIR /test
    RUN ls -al /
  • 执行build命令
    1
    2

    docker build -t openjdk11_alpine .
  • 运行
    1
    docker run -u test:test -it --name openjdk openjdk11_alpine
  • 查看java
    1
    java -version

java -version

查看docker容器信息

1
docker inspect 容器id/容器名字

docker inspect info

docker cache信息

  • 查看
    1
    docker system df
  • 删除