• Docker基础详细讲解,看这一篇就够了!


    Docker的详细讲解

    一、Docker概述

    1.Docker的作用

    一款产品的开发往往需要多个开发环境,在以前,开发人员将项目打包好之后,经常会出现在我的电脑上能够正常运行,而在他的电脑上不能使用,原因就是产品开发所需要的环境不一样。

    而现在,开发人员将产品以及它所对应的开发环境一起打包,这种就被称为镜像。这样就省去了开发环境的麻烦。

    而docker的出现就是为了解决以上的问题,docker就相当于一个箱子(镜像),把每一个镜像隔离开来,互不干扰

    2.Docker的好处

    1. 更能高效地利用资源,减去了硬件虚拟以及完整系统等额外的开销
    2. 更快的启动速度,Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间
    3. 运行环境的一致性,方便了应用的迁移,可以将在一个平台上的应用直接放在另一个平台上,不用担心开发环境的变化
    4. 同样也使得开发人员对于应用的维护和更新更加方便
    Docker容器虚拟机(VM)
    操作系统与宿主共享操作系统宿主机上运行宿主机的操作系统
    存储大小镜像小,便于存储与传输镜像庞大(VMDK)
    运行性能几乎无额外的性能损失操作系统额外CPU、内存消耗

    为什么Docker会比虚拟机快的多?

    • Docker容器是直接使用的宿主的操作系统,这就意味着docker的硬件资源不用虚拟化,这就减低了操作系统的等内存额外的损耗
    • Docker不需要直接加载操作系统,不会浪费资源。

    二、Docker的基本组成

    1.镜像

    镜像就相当于一个印刷机的模板,可以通过镜像来创建多个容器,也就是可以靠印刷机的模板印刷出很多相同的书籍,各个容器之间相互独立。

    2.容器

    • 容器就是一个一个独立的应用,每个应用之间相互独立
    • 可以被启用、开始、停止、删除。足够安全
    • 可以把容器看作是一个简易版的Linux系统(包括root用户权限,进程空间,用户空间和网络空间等)和运行在其中的应用程序。

    3.仓库

    • 仓库是集中存放镜像文件的地方。
    • 仓库和仓库注册服务器(Registry)是有区别的,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签
    • 仓库分为公开仓库(public)和私有仓库(private)两种形式
    • 最大的仓库是国外的Docker Hub,存放了大量的镜像文件。

    三、Docker的工作原理

    1.Docker的工作原理

    Dokcer是一个Client-Server结构:Docker守护进程运行在主机上,通过Socket从客户端来访问这个守护进程,而守护进程接收到来自客户端的命令后,管理运行在主机上的容器以及进行资源的分配。

    在这里插入图片描述

    2.Docker镜像加载的原理

    docker的镜像实际上是由一层一层的文件系统组成,这种层级的文件系统被称为UnionFS

    UnionFS(联合文件系统):是一种分层并且轻量级以及高性能的文件系统,支持对文件系统的修改,作为一次提交来一层一层的叠加,同时可以将不同的目录挂载到同一个虚拟文件系统下。镜像可以通过分层来继承、基于基础的镜像,可以制作各种具体的应用镜像。

    特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录,如下图

    在这里插入图片描述

    但我们最终会看到

    在这里插入图片描述

    Docker镜像加载原理

    典型的Linux文件系统由两部分组成,具体的原理就是:

    1. 首先启动bootfs(boot file system) :主要包含bootloader和Kernel,bootloader是引导加载内核Kernel到内存中,当加载镜像的时候,最底层就是bootfs。加载完毕后就被卸载了
    2. 再次启动rootfs(root file system) :在bootfs之上,包含Linux中典型的文件如/etc,/bin等标准目录和文件

    启动完之后,所有的docker镜像都起源于一个基础镜像,当进行修改或增加内容时,就会在当前的镜像之上创建新的镜像层。

    具体的来说就是:将挂载到统一虚拟文件系统下的多个目录分别设置成read-only,read-write等权限,而写操作实在read-only上的一种增量操作,不会影响到read-only目录。只会在此基础上进行操作。

    img

    总结:对于一个精简的OS来说,rootfs可以非常小,只需要包含基本的命令,工具和程序库就可以了,底层与宿主机共用一个内核,镜像本身只需要提供一个rootfs就可以了,这也就是为什么虚拟机往往几十G,而镜像容器只有几百M的原因。

    四、Docker的命令使用

    img

    1.帮助命令

    # 显示docker的版本信息
    docker version
    
    #显示docker的系统信息
    docker info
    
    #帮助命令
    docker 命令 --help
    

    在这里,如果你不是root用户,使用docker命令会频繁的需要sudo提权,所以为了解决这个问题,可以参考一下答案

    #添加docker用户组,如果已经有了可以跳过
    sudo groupadd docker 
    
    #将user1用户加入到docker组中
    sudo gpasswd -a user1 docker
    
    #更新docker用户组
    newgrp docker
    

    如果你忘记了你的root的密码,并且你目前的用户可以提权,你可以做以下操作

    sudo su root
    passwd
    # 然后重新设置密码
    

    2.镜像命令

    查看镜像

    # 查看本机上所有的镜像
    docker images
    # 出现以下信息
    REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
    hello-world   latest    bf756fb1ae65   12 months ago   13.3kB
    
    # 解释
    REPOSITORY	镜像仓库源
    TAG			镜像的标签
    IMAGE ID	镜像的ID
    CREATED		镜像的创建时间
    SIZE		镜像大小
    
    #可以附带的参数
    --all ,-a 列出所有的镜像
    --quiet ,-q只显示镜像的ID
    

    搜索镜像

    docker search 镜像名
    

    下载镜像

    # 不指定版本默认是最新版的
    docker pull 镜像名
    
    # 指定版本下载,以mysql为例子
    docker pull mysql:5.7
    

    删除镜像

    # 删除一个特定的镜像
    docker rmi -f 镜像的ID
    
    # 删除多个特定的镜像
    docker rmi -f 镜像的ID 镜像的ID ...
    
    # 删除所有镜像
    docker rmi -f $(docker images -aq)
    
    # 所有的镜像ID可以换成镜像名字
    

    3.容器命令

    创建容器

    docker run [可选参数] image 标识
    	--name 给容器命名
    	-d 后台运行
    	-it 交互式运行,进入容器内,开机并启动进入终端
    		-i 交互式
    		-t 终端
    	-p端口转发,指定容器的端口
    		-p 主机端口:容器端口
    	-P 随机端口
    
    # 进入容器的终端
    docker run -it 容器 /bin/bash
    

    查看容器状态

    docker run -d --name ubuntu01 ubuntu
    
    # 查看所有的容器的状态
    docker ps -a 
    
    # 判断当前正在进行的容器
    docker ps
    
    # 查看最近创建的1个容器
    docker ps -n=1
    

    启动和停止容器

    # 启动容器
    docker start ID
    
    # 重启容器
    docker restart ID 
    

    容器的进入

    # 开启容器
    docker start ID
    
    # 进入容器,exit退出后会关闭容器的运行,进入后不会开辟新的终端
    docker attach ID
    
    # 进入容器,exit退出后不会关闭容器,会开辟一个新的终端
    docker exec -it ID /bin/bash
    

    停止容器

    # 暂停,内存不会释放相当于注销
    docker stop
    
    # 杀掉容器,内存释放,相当于关机
    docker kill
    

    删除容器

    #查看容器内部的进程
    docker top ID
    
    #删除容器
    docker rm 容器ID	
    
    clear#删除所有容器
    docker rm -f `docker ps -aq`
    

    注意:后台启动的容器,如果没有前台的进程来提供服务,这个后台进程就会停止!

    4.常用其他命令

    查看日志

    docker logs [可选参数] 容器ID
          --details        显示提供给日志的其他详细信息
      -f, --follow         跟踪日志输出
      -n, --tail string    指定要显示的日志条数 (默认为全部)
      -t, --timestamps     显示时间戳
    

    查考镜像元数据

    docker inspect 容器ID
    

    主机与容器文件进行传输

    #ubuntu01容器中test.py文件传输到本机bd文件夹下面。
    docker cp ubuntu01:/root/test.py /home/bd	
    
    #主机上的文件传到虚拟机上
    docker cp /home/bd/PythonEnv/ ubuntu01:/root 
    

    查看容器的资源消耗

    docker stats 容器的ID
    

    五、Docker实践

    1.部署Nginx

    docker search nginx
    
    docker pull nginx
    
    docker run -d --name nginx01 -p 3304:80 nginx
    
    docker exec -it nginx01 /bin/bash
    

    2.部署Tomcat

    docker run -d --name tomcat01 -p 3355:8080 tomcat
    

    3.部署elasticsearch和kibana

    docker run -d --name elasticsearch01 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2#开启服务
    

    服务器搭建ElasticSearch环境和kibana环境请看这里,注意这里不是利用docker搭建的

    4. Commit镜像

    一般的,我们通过镜像创建并启动容器,我们知道镜像是只读的,容器是可以写的,我们可以将这两者打包在一起组成一个新的镜像,这就叫做Commit镜像

    docker commit -m="提交所描述的信息" -a=“作者” 容器的id 你要打包成的镜像名:[版本]
    

    六、容器数据卷

    doker是将应用和环境打包成一个镜像,通过容器来进行使用,容器可以随时删除和卸载,但是这就i出现了一个问题,当容器被删除之后,容器里面的数据也会被随之删除,这显然不是我们想要的结果,所以才有了容器数据卷的诞生。

    数据卷技术的引入:我们希望Docker容器产生的数据可以自动同步到本地,这样容器删了数据并不会丢失;同时数据也可在容器之间共享。这就是卷技术,也就是目录的挂载。

    1.挂载的命令

    docker run -it --name ubuntu02 -v 主机目录:容器要同步的目录 Ubuntu /bin/bash 
    

    如果你忘记了自己挂载的具体路径可以使用下面的方法

    docker inspect 你想要查看的容器
    
    # 找到下面的这一栏
    "Mounts": [
                {
                    "Type": "bind",
                    "Source": "/home/docker/ubuntu02",#这就是那个资源目录
                    "Destination": "/home",
                    "Mode": "",
                    "RW": true,
                    "Propagation": "rprivate"
                }
    

    2.具名挂载和匿名挂载

    具名挂载

    # 匿名挂载: -v:容器内路径(没有写容器外路径),自动生成同步路径
    docker run -d -P --name nginx01 -v /etc/nginx nginx
    
    # 查看所有volume的情况,默认在/var/lib/docker/volumes路径下创exit建容器卷,文件名是随机生成的
    docker volume ls
    
    • 具名
      • -v 卷名:容器内路径
      • 文件名不是随机生成的
    • 指定路径挂载
      • -v 宿主机路径:容器内路径
    • 挂在后面加上:ro(只读),rw(只写)
    # 具名挂载: -v 卷名:容器内路径
    docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx nginx
    
    # 查看所有volume的情况
    docker volume ls
    
    # 查specific-nginx卷的具体信息
    docker volume inspect specific-nginx
    
    # 通过 容器内路径:ro/rw 限制读写权限
    ro:read only 	#只读,该路径文件只能通过宿主机来操作,容器内无法操作
    rw:read write	#可读可写
    
    docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx:ro nginx
    docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx:rw nginx
    

    3.数据卷容器

    docker run -it --name centos01 centos
    
    docker run -it --name centos02 --volumes-from centos01 centos
    
    docker run -it --name centos03 --volumes-from centos01 centos
    

    image-20210129181811436

    我们可以将docker01删除,但是docker01里面的数据就不会消失,而是保存在docker02和docker03之中。

    七、DockerFile

    1.Docker的简介

    DockerFile是用来创建docker镜像的文件

    image-20210129213822710

    构建镜像的步骤就是:

    1. 编写一个dockerFile文件
    2. docker build构建一个镜像
    3. docker run运行镜像
    4. docker push发布镜像

    2.DockerFile的构建

    1. 每个保留关键字(指令)都必须是大写
    2. 执行顺序是从上往下执行
    3. #代表注释
    4. 每条指令都会创建新的镜像层
    FROM基础镜像,从此开始构建
    MAINTAINER镜像作者,通常为姓名+邮箱
    RUN镜像构建时需要执行的命令
    ADD在镜像中需要添加的文件(比如基础镜像centos中要添加tomcat)
    WORKDIR镜像的工作目录
    VOLUME容器数据卷,挂载主机的目录
    EXPOSE对外的暴露端口
    CMD指定容器启动时要运行的命令(只有最后一个生效,可被替代)
    ENTRYPOINT指定容器启动时要运行的命令(可以追加命令)
    ONBUILD当构建一个被继承DockerFile时就会运行ONBUILD指令
    COPY类似ADD,将文件拷贝到镜像中
    ENV构建时的环境变量

    3.编写自己的DcokerFile

    3.1构建一个基础的Centos镜像

    首先要编写DockerFile文件

    FROM centos
    MAINTAINER wy<123456789@qq.com>
    
    ENV MYPATH /usr/local
    
    WORKDIR $MYPATH
    
    RUN yum -y install vim
    Rum yum -y install net-tools
    
    EXPOSE 8088
    
    CMD echo $MYPATH
    CMD echo "---end---"
    CMD /bin/bash
    

    命令: docker build -f dockerfile路径 -t 镜像名:[tag] .

    # 编写dockerfile文件,官方命名为Dockerfile,这样就不需要通过-f指定,build时会自动寻找这个文件
    docker build -f DockerFile的文件名字 -t mycentos:0.1 .
    

    注意:1. 一定在最后面有一个点的

    ​ 2.可能会出现这样的问题:

    Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist
    

    ​ 而上面的报错信息是因为CentOS Linux已经停止维护,官方推出了CentOS Stream项目,解决问题的原理请点击这里,更改之后的文件如下

    FROM centos
    MAINTAINER wy<123456789@qq.com>
    
    ENV MYPATH /usr/local
    
    WORKDIR $MYPATH
    
    RUN cd /etc/yum.repos.d/
    RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
    RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
    RUN yum makecache & update -y
    RUN yum -y install vim
    RUN yum -y install net-tools
    
    EXPOSE 8088
    
    CMD echo $MYPATH
    CMD echo "---end---"
    CMD /bin/bash
    
    3.2构建Tomcat镜像

    首先要准备Tomcat压缩包和JDK的压缩包,并将这两个压缩包放在服务器的同一个文件夹下

    # DockerFile文件的编写
    FROM centos
    MAINTAINER zsr <2476785771@qq.com>
    
    COPY readme.txt /usr/local/readme.txt
    
    ADD jdk-8u341-linux-x64.tar.gz /usr/local/
    ADD apache-tomcat-9.0.65.tar.gz /usr/local/
    
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    ENV JAVA_HOME /usr/local/jdk
    ENV CALSSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.65
    ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.65
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
    
    EXPOSE 8080
    CMD /usr/local/apache-tomcat-9.0.65/bin/startup.sh && tail -F /url/local/apache-tomcat-9.0.65/bin/logs/catalina.out
    

    八、Docker网络

    1.容器之间的网络互通

    可以用ip addr来查看服务器内部网络的地址,可以发现三个地址。

    • 127.0.0.1 本机回环地址
    • 172.17.223.207 服务器内网IP地址
    • 172.18.0.1docker0的地址
    docker是如何处理容器网络访问的?比如有一个tomcat容器,一个mysql容器;tomcat中运行着一个web项目,这个项目需要访问mysql。这是如何实现的呢?
    
    • 每启动一个容器,docker就会给容器分配一个ip地址,并且每次新增的网络地址都是一对一对的,这就是evth-pair技术。

    • 就是一对虚拟设备接口,成对出现,一段连着协议,一段彼此相连;容器内的88连接了主机的89,容器内的90连接了主机的91;

    • evth-pair充当了一个桥梁,实现了主机可以ping通容器内部ip地址,用于连接各种虚拟网络设备

    那么 tomcar01和tomcat02 这两个容器能否ping通呢?

    当然是可以的,因为两个容器内的ip地址都桥接了主机相应的ip地址,都与docker0地址处于同一网段,因此可以ping通,容器和容器之间是可以ping通的

    image-20210216214529859

    所有的容器在不指定网络的情况下,都是docker0路由分配的,容器被删除之后,与此相对的网络也会被删除

    image-20210216221256027

    2.自定义网络

    # 查看所有的网络	
    [root@zsr ~]# docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    81fa37acd3b5   bridge    bridge    local
    d1c3276f2d1f   host      host      local
    40b12350fa4a   none      null      local
    

    当我们启动容器的时候会有默认的参数就是 --net bridge,也就是docker0

    但是建议自定义网络

    # 创建一个网络mynet,采用默认的桥接模式,子网地址192.168.0.0,网关192.168.0.1
    
    docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
    2e6be259e1f43f884fbf9e24aa3cc1b238b91bd1e9be3ba0abcfbefd3e106450
    
    docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    81fa37acd3b5   bridge    bridge    local
    d1c3276f2d1f   host      host      local
    2e6be259e1f4   mynet     bridge    local
    40b12350fa4a   none      null      local
    
    #查看自定义的网络的详细信息
    docker network inspect mynet
    

    优点:解决了docker0的弊端,可以直接通过容器名来访问,

    应用:在不同的集群(redis,mysql)用不同的网络,使用自己的子网,保证集群的安全及健康

    docker exec -it mynet-tomcat01 ping mynet-tomcat02
    

    现在问题来了,tomcat01与mynet-tomcat01之间不互通,又该怎么办呢?

    image-20210220234313302

    解决办法

    # 测试联通tomcat01到mynet-tomcat01
    docker network connect mynet tomcat01
    # 原理就是将tomcat01加入到了mynet的网络中
    

    3.实现Redis集群部署

    image-20210220235432787

    3.1自定义一个网络
    # 自定义一个网络
    docker network create redis --subnet 172.38.0.0/16
    
    # 通过脚本创建6个redis配置
    for port in $(seq 1 6); \
    do \
    mkdir -p /mydata/redis/node-${port}/conf
    touch /mydata/redis/node-${port}/conf/redis.conf
    cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
    port 6379
    bind 0.0.0.0
    cluster-enabled yes
    cluster-config-file nodes.conf
    cluster-node-timeout 5000
    cluster-announce-ip 172.38.0.1${port}
    cluster-announce-port 6379
    cluster-announce-bus-port 16379
    appendonly yes
    EOF
    done
    
    3.2创建六个容器
    for ps in$(seq1 6);\
    do \
    docker run -d -p 637${ps}:6379 -p 1637${ps}:16379 --name redis-${ps} \
    -v /mydata/redis/node-${i}/data:/data \
    -v /mydata/redis/node-${i}/conf/redis.conf:/etc/redis/redis.conf \
    --net redis --ip 172.38.0.1${ps} redis:6.0 redis-server /etc/redis/redis.conf
    done
    
    3.3查看集群信息
    # 进入redis-1容器
    docker exec -it redis-1 /bin/sh
    # pwd
    /data
    # ls
    appendonly.aof	nodes.conf
    
    # 配置集群
    redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
    
    
    # 连接集群查看信息
    redis-cli -c
    
    # 查看集群信息
    cluster info   
    
    # 查看集群节点信息,三主三从
    cluster nodes    
    

    实现了高可用,主机挂掉从机自动替代主机,效率极大的提高!

  • 相关阅读:
    求最大公约数
    Ribbon讲解
    求臻医学:实体肿瘤FDA/NMPA新获批抗癌药物/适应症盘点
    并发包下的 Unsafe 类
    Java设计模式 _行为型模式_观察者模式
    收银系统商品定价设计思考
    leetcodetop100(18) 螺旋矩阵
    Canal+Kafka实现MySQL与Redis数据同步(一)
    结构体高级应用(变量位置 大小 位域 共用体)
    排序算法之-选择
  • 原文地址:https://blog.csdn.net/Indra_ran/article/details/126960453