Docker容器技术

认识 docker

一、为什么学习 docker

  • 使用背景
    	某公司的产品运行在内部的虚拟化平台中,如openstack,也就是我们所学的KVM虚拟化,创建虚拟机。但是不断增加的云端应用,增加了对硬件资源的消耗,不断的创建虚拟机,给公司带来了难题,公司已经在云平台上运行了多台云主机,消耗了大量的硬件资源。怎么才能够高效的利用硬件资源实现云服务呢?容器技术,此时就派上用场了。
    	
    	一个公司,它内部所有的应用系统,都是运行在公司内部的虚拟机平台(网站)的。这个平台是通过Linux技术,Openstack搭建的,可以非常方便的管理公司的服务器资源,进行快捷的虚拟机创建,删除,扩容,缩容等等。功能类似于vmware workstation图形化工具创建虚拟机,运行完整的操作系统,用于运行各种应用.
    
  • docker 优势
    • docker 更高效的利用系统资源

      容器不需要进行硬件虚拟化以及运行一个完整操作系统的额外开销,docker对系统资源的利用率更高,无论
      是应用执行,文件存储,还是在内存消耗等方面,都比传统虚拟机更高效。因此一个同样配置的主机,可以
      运行处更多数量的容器实例。
      
    • 更快的启动时间

      传统的虚拟机启动时间较久,docker容器直接运行在宿主机的内核上,无须启动一个完整的操作系统,因此可以达到秒级启动,大大的解决开发,测试,部署的时间。
      
    • 一致性的环境

      在企业里,程序从开发环境,到测试服务器,到生产环境,难以保证机器环境一致性,极大可能出现系统依赖冲突,导致难以部署等Bug。然而利用docker的容器-镜像技术,提供了除了内核以外完整的运行时环境,确保了应用环境的一致性。利用docker的镜像,部署,迁移项目还可以跨系统平台.
      
    • 持续交付和部署

      还是刚才所说的一致性的环境,对于开发和运维的人员,最希望的就是环境部署迁移别处问题,利用docker可以定制镜像,以达到持续集成,持续交付和部署。通过Dockerfie来进行镜像构建,实现系统集成测试,运维进行生产环境的部署方便技术团队能够快速理解运行环境部署流程. 且Dockerfile可以使镜像构建透明化,
      
    • 更轻松的迁移

      Docker可以在很多平台运行,无论是物理机,虚拟机,云服务器等环境,运行结果都是一致的。用于可以轻松的将一个平台的应用,迁移到另一个平台,而不用担心环境的变化,导致程序无法运行。
      

二、容器和虚拟机的差异

  • 传统虚拟机技术
    • 基本介绍

      虚拟机是虚拟出一套硬件,在其上面运行一个完整的操作系统,例如我们使用KVM,指定系统镜像,然后装
      系统,最终可以使用,在该系统上再运行所需的应用程序。
      KVM创建虚拟机时,指定较少的cpu,内存,硬盘等资源,虚拟机性能较低。
      
    • 传统虚拟机技术原理

      传统虚拟机技术原理

  • 容器技术
    • 基本介绍

      容器内的应用程序直接运行在宿主机的内核上,容器内没有自己的内核,也没有对硬件进行虚拟,因此容器比起虚拟机更为轻便。
      
    • 容器技术原理

      容器技术原理

  • 创建容器过程
    • 获取镜像,如 docker pull centos ,从镜像仓库拉取
    • 使用镜像创建容器
    • 分配文件系统,挂载一个读写层,在读写层加载镜像
    • 分配网络/网桥接口,创建一个网络接口,让容器和宿主机通信
    • 容器获取IP地址
    • 执行容器命令,如/bin/bash
    • 反馈容器启动结果

三、docker最核心的组件

  • image 镜像: 构建容器(我们讲应用程序运行所需的环境,打包为镜像文件)。

    镜像是一个只读模板,用于创建容器,也可以通过Dockerfile文本描述镜像的内容,镜像的概念类似于编程开发里面向对象的类,从一个基类开始(基础镜像Base lmage)构建容器的过程,就是运行镜像,生成容器实例。Docker镜像的描述文件是Dockerfile,包含了如下的指令:
      - FROM 定义基础镜像
      - MAINTAINER 作者
      - RUN 运行Linux命令
      - ADD 添加文件/目录
      - ENV 环境变量
      - CMD 运行进程
    
  • Container 容器:

    对于容器的理解:
      - 容器是一种特殊的、具有高度隔离性和可移植性的运行环境
      - 可以将其视为宿主机上的一种特殊类型的“应用”
    
    容器是一个镜像的运行实例,创建容器的过程:
      - 获取镜像,如 docker pullcentos,
      - 从镜像仓库拉取
      - 使用镜像创建容器
      - 分配文件系统,挂载一个读写层,在读写层加载镜像
      - 分配网络/网桥接口,创建一个网络接口,让容器和宿主机通信
      - 容器获取IP地址
      - 执行容器命令,如/bin/bash
      - 反馈容器启动结果。
    
    容器与镜像的关系:
      - 基础与实例:镜像是容器的基础模板,容器是基于镜像创建的运行实例。
      - 只读与读写:镜像为只读,包含了运行应用所需的基础配置和文件系统;容器在镜像基础上增加了可读写层,允许在运行时进行修改。
      - 依赖与独立:容器依赖于创建时所基于的镜像,但每个容器又有一定的独立性,拥有自己的进程、网络和文件系统视图。
      - 共享与隔离:多个容器可以基于同一个镜像创建,共享镜像的只读部分,同时各自的运行环境相互隔离。
      - 更新影响:镜像的修改或更新影响新创建的容器,已创建的容器通常不会自动更新,除非基于新镜像重新创建。
    
  • Registry 镜像仓库: (保存镜像文件,提供上传,下载镜像)作用好比github.

    Docker镜像需要进行管理,docker提供了Registry仓库,其实它也是一个容器。可以用于可以基于该容器运行私有仓库。也可以使用Docker Hub互联网公有镜像合库
    
  • Dockerfile: 将你部署项目的操作,写成一个部署脚本,这就是dockerfile,且该脚本还能够构建出镜像文件

四、docker 工作机制和运行环境

  • Docker 引擎

    docker引擎

  • Docker 平台组成

    docker平台组成

  • docker 容器生命周期图

    docker生命周期

  • docker实际使用场景(虚拟机上安装Linux操作系统,在Linux系统上安装docker

    docker使用场景示例

五、Docker 镜像原理解析

  • Docker 分层镜像
    • 写时拷贝特性

      镜像分享一大好处就是共享资源,例如有多个镜像都来自于同一个base镜像,那么在docker host只需要存储一份base镜像。内存里也只需要加载一份host,即可为多个容器服务。即使多个容器共享一个base镜像,某个容器修改了base镜像的内容,例如修改/etc/下配置文件,其他容器的/etc/下内容是不会被修改的,修改动作只限制在单个容器内,这就是容器的写入时复制特性(Copy-onwrite)
      
    • Docker 分层镜像原理

      • 分层原理示意图

        docker镜像分层原理

      • 容器的增删改查操作说明

        文件操作 说明
        添加文件 在容器中创建文件时,新文件被添加到容器层中。
        读取文件 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。
        修改文件 在容器中修改已存在的文件时,Docker会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。
        删除文件 在容器中删除文件时,Docker也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。(只是记录删除操作)
      • 分层原理总结

        1. 所有对容器的修改动作,都只会发生在 容器层 里,只有 容器层 是可写的,其余 镜像层 都是只读的。
        2. 只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
        3. 这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改所以镜像可以被多个容器共享。
        
  • Docker 镜像的内容
    • 说明

      1. Docker镜像代表一个容器的文件系统内容
      2. 镜像层级技术属于 联合文件系统
      3. 容器是一个动态的环境,每一层镜像里的文件都属于静态内容;dockerfile里的ENV、VOLUME、CMD等内容都会落实到容器环境里
      
    • 联合文件系统示意图

      UnionFS

六、问题

  • win为什么可以使用docker , docker 不是需要依赖linux内核吗?
    Windows 可以使用 Docker 主要是通过以下几种方式实现的:
    1. Windows 上的 Docker Desktop:
    Docker Desktop for Windows 利用了 Windows 内置的 Hyper-V 虚拟化技术。它创建了一个轻量级的 Linux 虚拟机(VM)来运行 Docker 引擎。这个虚拟机基于 Linux 内核,从而能够支持 Docker 的运行。
    
    2. Windows 容器:	
    Windows Server 2016 及更高版本支持 Windows 容器。虽然 Windows 容器和基于 Linux 的 Docker 容器有所不同,但它们也是一种容器技术,适用于 Windows 特定的应用场景。
    
  • docker镜像为什么才几百兆?
    因为docker镜像只有rootfs和其他镜像层,共用宿主机的linux内核(bootfs),因此很小!docker镜像为什么才几百兆?
    Bootfs(boot-file sysmtem)主要包含bootloader和kernel,bootloader主要是引导加载kernel; Linux刚启动时会加载bootfs文件系统
    
  • 为什么下载一个 dockernginx镜像需要133MB? nginx安装包不是才几兆吗?
    因为docker的nginx镜像是分层的,nginx安装包的确就几M,但是一个用于运行nginx的镜像文件,依赖于父镜像(上一层)和基础镜像(发行版),所以下载的nginx镜像有一百多兆.
    

CentOS 系统安装 docker

一、前置工作

提前准备好一个宿主机(vmware去创建一个1inux机器,然后安装docker去使用),或者使用ECS云服务器安装docker使用

二、基础环境配置

# 更新阿里云的yum源(基础仓库和epel额外的仓库)
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

# 清除缓存、生成缓存
yum clean all && yum makecache

# 清空flush所有的 iptables 规则
iptables -F
# 查看当前 SELinux(Security-Enhanced Linux)的运行模式, 需要为Disabled 状态
getenforce 

# 安装基础依赖
yum install bash-completion vim lrzsz wget exDect net-tools nc nmab tree dos2unix htop iftop iotop unzip telnet sl psmisc nethogs glances bc ntpdate openldap-devel

# 禁止开机自启并关闭防火墙
systemctl disable firewalld
systemctl stop firewalld

# 启动防火墙服务/重新启动防火墙服务
# sudo systemctl start firewalld
# sudo systemctl restart firewalld
# 使防火墙服务开机自启
# sudo systemctl enable firewalld
# 查看防火墙状态
# sudo systemctl status firewalld

三、安装 docker

  • 安装说明
    # 安装说明: docker必须安装在centos7平台,内核版本不低于3.10; 在centos平台运行docker可能会遇见些告警信息,修改内核配置参数,打开内核转发功能;
    # 查看操作系统发行版本
    cat /etc/redhat-release
    # 查看centos内核版本 
    uname -r
    # 内核版本过低更新指令 (不要再生产环境操作)
    yum update
    
  • 安装 docker
    • 开启 linux 内核的流量转发

      # 获取dockers.conf配置参数
      cat <<EOF > /etc/sysctl.d/docker.conf
      net.bridge.bridge-nf-call-ip6tables = 1
      net.bridge.bridge-nf-call-iptables = 1
      net.ipv4.conf.default.rp filter = 0
      net.ipv4.conf.all.rp_filter = 0
      net.ipv4.ip forward = 1
      EOF
      
      # 加载修改内核的参数,配置文件
      modprobe br_netfilter
      sysctl -p /etc/sysctl.d/docker.conf
      
    • 利用 yum 快速安装docker

      # 提前配置好yum仓库
      # 1.阿里云自带仓库 2.阿里云提供的docker专属repo仓库
      curl -o /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo
      curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
      
      # 更新yum缓存
      yum clean all && yum makecache
      
      # 可以直接yum安装docker了
      # 查看源中可用版本
      yum list docker-ce --showduplicates | sort -r
      # 选择指定版本使用yum安装 (-y 选项的含义是在安装过程中自动回答“yes”,即自动确认所有的提示和默认选项,无需手动进行确认)
      yum install docker-ce-20.10.6 -y
      # 卸载docker
      yum remove -y docker-xxx
      
  • docker 启动与停止
    # 开机自启
    sudo systemctl enable docker
    # 启动
    sudo systemctl start docker
    # 停止
    sudo systemctl stop docker
    # 重启
    sudo systemctl restart docker
    

Ubuntu 系统安装 docker

一、基础环境配置

# 查看防火墙状态
sudo ufw status
# 开启防火墙
sudo ufw enable
# 关闭防火墙
sudo ufw disable

二、安装 docker

  • 安装 docker
    • 开启 linux 内核的流量转发

      # 获取dockers.conf配置参数
      cat <<EOF > /etc/sysctl.d/docker.conf
      net.bridge.bridge-nf-call-ip6tables = 1
      net.bridge.bridge-nf-call-iptables = 1
      net.ipv4.conf.default.rp filter = 0
      net.ipv4.conf.all.rp_filter = 0
      net.ipv4.ip forward = 1
      EOF
      
      # 加载修改内核的参数,配置文件
      modprobe br_netfilter
      # 这种方式可能存在一些潜在的风险;通常情况下,为了更安全和更可控,还是建议先打开 /etc/sysctl.conf 文件,确认内容和格式后再进行追加操作
      sudo cat /etc/sysctl.d/docker.conf >> /etc/sysctl.conf
      
    • 快速安装docker

      # 改用国内的镜像站安装docker(其他镜像站参考:https://blog.csdn.net/qianzhitu/article/details/140225287)
      # 更新软件包列表
      sudo apt-get update
      sudo apt-get install ca-certificates curl
      sudo install -m 0755 -d /etc/apt/keyrings
      sudo curl -fsSL https://mirrors.163.com/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker-163.asc
      sudo chmod a+r /etc/apt/keyrings/docker-163.asc
      echo \
        "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker-163.asc] https://mirrors.163.com/docker-ce/linux/ubuntu \
        $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker-163.list > /dev/null
      # 再次更新软件包列表
      sudo apt-get update
      # 安装 Docker 引擎
      sudo apt install docker-ce
      
  • docker 启动与停止
    # 开机自启
    sudo systemctl enable docker.service
    sudo systemctl enable docker.socket
    # 启动
    sudo service docker start
    # 停止
    sudo service docker stop
    # 重启
    sudo service docker restart
    

配置 docker 加速器

一、配置说明

使用docker首要操作就是获取镜像文件,默认下载是从Docker Hub下载,网速较慢,国内很多云服务商都提供了加速器服务,阿里云加速器,aocloud加速器,灵雀云加速器。配置加速器可以加速镜像文件的下载

二、配置 docker 加速器

# 创建配置文件
mkdir -p /etc/docker
touch /etc/docker/daemon.json
vim /etc/docker/daemon.json

# 重启docker
# centos 重启docker
sudo systemctl restart docker
# ubuntu 重启docker
sudo service docker restart
  • daemon.json 配置文件
    {
        "registry-mirrors": [
            "https://isj3n34q.mirror.aliyuncs.com"
        ]
    }
    

三、查看 docker 启动情况

# 查看docker进程
ps -ef|grep docker
# 启动成功示例
root     16987     1  1 21:23 ?        00:00:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root     17114 16624  0 21:23 pts/1    00:00:00 grep --color=auto docker

# 查看docker是否正确启动
sudo docker version
# 启动成功示例
Client: Docker Engine - Community
 Version:           26.1.4
 API version:       1.41 (downgraded from 1.45)
 Go version:        go1.21.11
 Git commit:        5650f9b
 Built:             Wed Jun  5 11:32:04 2024
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          20.10.6
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       8728dd2
  Built:            Fri Apr  9 22:43:57 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.33
  GitCommit:        d2d58213f83a351ca8f528a95fbd145f5654e957
 runc:
  Version:          1.1.12
  GitCommit:        v1.1.12-0-g51d5e94
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

docker 实践操作

【实操一】:使用 Nginx 搭建一个 Web 服务器

  • 在宿主机上使用 Nginx 搭建一个 Web 服务器步骤:
    1. 开启服务器
    2. 在服务器上安装好运行nginx所需的依赖关系
    3. 安装nginx yum install nginx -y
    4. 修改nginx配置
    5. 启动nginx
    6. 客户端访问nginx
    
    这是一个比较耗时的操作..
    
  • docker 中使用 Nginx 搭建一个 Web 服务器步骤:
    • 1 - 获取镜像,获取是从你配置好的 docker 镜像站中,去拉取nginx镜像

      # 在镜像仓库搜索镜像
      docker search nginx
      # 拉取下载 nginx 镜像(拉取失败可以考虑修改 daemon.json 文件中的镜像网址)
      docker pull nginx
      # 查看镜像
      docker image ls
      
    • 2 - 运行该 nginx 镜像,运行出具体的容器,然后这个容器中,就跑着一个nginx服务

      # 运行镜像指令 (会返回一个容器的id)
      # docker run 参数 镜像的名字
      
      # 参数说明:
      # [-d]: 后台运行容器
      # [-p 80:80]: 端口映射,宿主机端口:容器内端口
      docker run -d -p 80:80 nginx
      
      # 查看有哪些容器在运行
      docker ps
      # 查看所有容器
      docker ps -a
      
      # 此时可以访问宿主机的80端口,查看到容器内的80端口的应用是什么了
      # 安全组规则:阿里云有安全组的设置,您需要确保在安全组中开放了 80 端口的入站规则,允许外部访问。你可以在阿里云控制台的安全组配置中进行设置
      http://39.99.253.236:80/
      
      # 停止容器
      # docker stop 容器id
      docker stop f61a583e5775
      # 重新启动容器
      docker start f61a583e5775
      

【实操二】:使用 docker 部署静态文件格式课件

  • 复制本地课件到服务器
    # 在服务器创建course用来保存课件
    mkdir /root/course
    
    # scp -r 课件所在路径\Django课件 服务器用户名@服务器IP:服务器保存课件的目录路径
    scp -r 课件所在路径\Django课件 root@remote-server:/root/course
    
  • 在服务器启动并创建容器
    # 使用my_nginx镜像在后台运行
    docker run --name=course_for_django -d -p 8000:80 -v /root/course/Django课件/:/usr/share/nginx/html my_nginx
    
  • http 访问测试
    http://39.99.253.236:8000
    

【实操三】:使用 docker 切换不同的发行版,内核使用的都是宿主机的内核

  • 示意图

    使用docker切换不同发行版

  • 操作步骤
    # 拉取镜像
    docker pull centos:8
    docker pull ubuntu
    
    # 查看当前系统发行版本
    cat /etc/redhat-release
    >> CentOS Linux release 7.8.2003 (Core)
    exit
    
    # 以交互模式运行一个centos系统的容器,并进入终端
    docker run -it centos:8 bash
    # 查看容器内系统的发行版本
    cat /etc/redhat-release
    >> CentOS Linux release 8.4.2105
    exit
    
    # 以交互模式运行一个ubuntu系统的容器,并进入终端
    docker run -it ubuntu bash
    # 查看容器内系统的发行版本
    cat /etc/lsb-release
    >> DISTRIB_ID=Ubuntu
    >> DISTRIB_RELEASE=20.04
    >> DISTRIB_CODENAME=focal
    >> DISTRIB_DESCRIPTION="Ubuntu 20.04.3 LTS"
    exit
    

DockerFile 镜像定制

一、定制 Docker 镜像的方式

  • 手动修改容器(docker commit)内容,导出新的镜像
  • 基于Dockerfile自行编写指令,基于指令流程创建镜像

二、Dockerfile 主要组成部分:

# 基础镜像信息
FROM centos
# 制作镜像操作指令
RUN yum insatll openssh-server -y
# 容器启动时执行指令 
CMD["/bin/bash"]

三、Dockerfile 指令

FROM 		这个镜像的妈妈是谁?	=> (指定基础镜像)
MAINTAINER 	告诉别人,谁负责养它?	=> (指定维护者信息,可以没有)
RUN 		你想让它干啥	=>	(在命令前面加上RUN即可)
ADD 		给它点创业资金  =>  (添加宿主机的文件到容器内,会自动解压)
WORKDIR 	我是cd,今天刚化了妆  =>  (设置当前工作目录)
VOLUME 		给它一个存放行李的地方	 =>  (设置卷,挂载主机目录)
EXPOSE 		它要打开的门是啥  =>  (指定对外的端口,宿主机在容器内暴露一个窗口) 
CMD 		奔跑吧,兄弟!   =>  (指定容器启动后的要干的事情)
COPY		(复制文件,作用和ADD是一样的,都是拷贝宿主机的文件到容器内, 仅拷贝不会自动解压)
ENV			(环境变量)
ENTRYPOINT	(容器启动后执行的命令)

四、Dockerfile 指令操作

  • COPY 拷贝
    # COPY指令能够保留源文件的元数据,如权限,访问时间等等,这点很重要
    # copy指令从宿主机复制文件目录到新的一层镜像内
    COPY FengLing.py /home/
    
    # 支持多个文件,以及通配符形式复制,语法要满足Golang的filepath.Match
    # Fengling、Feng1、cc.txt、ccA.txt均会被复制到镜像的 /home/ 目录
    COPY Feng* /tmp/cc?.txt /home/
    
  • ADD 添加
    特性和COPY基本一致,不过多了些功能
    1.源文件是一个URL,此时docker引擎会下载该链接,放入目标路径,且权限自动设为600、若这不是期望结果,还得增加一层RUN指令
    2.源文件是一个URL,且是一个压缩包,不会自动解压,也得单独用RUN指令解压
    3.源文件是一个压缩文件,且是gzip,bzip2,xz,tar情况,ADD指令会自动解压缩该文件到目标路径
    
    ADD Feng.tgz /home/
    # 不是期望结果执行RUN指令
    RUN xxx修改指令
    
  • CMD 执行指令
    • 基本使用

      # 在指定了entrypoint指令后,用CMD指定具体的参数(注意: 参数只能用双引号"" 包裹)
      # docker不是虚拟机的概念,容器就是一个进程,既然是进程,那么程序在启动的时候需要指定些运行参数,这就是CMD指令作用
      CMD ["参数1", "参数2"]
      
      # 例如centos镜像默认的CMD是/bin/bash(即CMD ["/bin/bash"]),直接docker run -it centos会直接进入bash解释器;
      docker run -it centos
      
      # 也可以启动容器时候,指定参数
      docker run -it centos cat /etc/os-releasea
      # 指定参数在dockerfile中的等效写法
      CMD ["cat", "/etc/os-releasea"]
      
    • CMD 使用注意

      # docker不是虚拟机的概念,虚拟机里的程序运行,基本上都是在后台运行,利用systemct运行,但是容器内没有后台进程的概念,必须在前台运行。
      # 容器就是为了主进程而存在的,主进程如果退出了,容器也就失去意义,自动退出
      
      # 这样的写法是错误的,容器会立即退出,因为systemctl start nginx是希望以守护进程形式启动nginx,且CMD命令会转化为如下格式。这样的命令主进程是sh解释器,执行完毕后立即结束了,因此容器也就退出了
      CMD systemctl start nginx
      CMD ["sh", "-c",  "systemctl start nginx"]
      
      # 正确写法
      CMD ["nginx", "-g", "daemon off;"]
      
  • ENTRYPOINT 启动后执行指令
    • 指令执行的两种方式 (同 CMD 指令)

      1. exec
      2. shell
      
    • 作用

      作用和CMD一样,都是在指定容器启动程序以及启动参数。
      
    • CMD 指令区别

      指定使用ENTRYPOINT去执行指令后; 可以接收容器启动时,传递过来的启动参数并与dockerfile中的ENTRYPOINT指令参数组成新的参数去执行,而不是覆盖dockerfile中的CMD指令参数
      
    • 使用演练

      • 创建 Dockerfile

        FROM centos:7.8.2003
        
        # 创建备份目录
        RUN mkdir -p /etc/yum.repos.d/backup/
        # 备份原有 yum 源配置文件
        RUN mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/
        # 下载并使用国内阿里云的 yum 源配置
        RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
        # 更新 yum 并安装 curl
        RUN yum update -y && yum install -y curl
        
        # ---------- 【使用CMD指令】 -------------
        CMD ["curl", "-s", "http://ipinfo.io/ip"]
        # ---------- 【使用ENTRYPOINT指令】 -------------
        ENTRYPOINT ["curl", "-s", "http://ipinfo.io/ip"]
        
      • 构建使用镜像

        # ------------- 使用CMD指令创建的Dockerfile -------------
        # 构建镜像 -t 指定创建的镜像名称
        docker build .
        docker build -t 镜像名 .
        # 查看创建好的镜像
        docker images
        # 修改镜像名字
        docker tag 58770b6b456a centos_curl_cmd
        
        # 1.运行镜像 - 不带启动参数
        curl -s http://ipinfo.io/ip
        >> 39.99.253.666
        docker run centos_curl_cmd
        >> 39.99.253.666
        
        # 2.运行镜像 - 携带启动参数
        curl -s http://ipinfo.io/ip -I
        >> HTTP/1.1 405 Method Not Allowed
        >> date: Mon, 05 Aug 2024 06:07:06 GMT
        >> content-type: text/plain; charset=utf-8
        >> ...
        # 无法携带 "-I" 参数到CMD指令中curl 
        docker run centos_curl_cmd -I
        >> docker: Error response from daemon: failed to create shim task
        # "pwd" 作为centos_curl的启动参数, 覆盖了Dockerfile文件中CMD指令
        docker run centos_curl_cmd pwd
        >> /
        
        # ------------- 使用ENTRYPOINT指令创建的Dockerfile -------------
        # 构建镜像
        docker build .
        # 查看创建好的镜像
        docker images
        # 修改镜像名字
        docker tag 5134c40e0a25 centos_curl_entrypoint
        
        # 1.运行镜像 - 不带启动参数
        docker run centos_curl_entrypoint
        >> 39.99.253.666
        
        # 2.运行镜像 - 携带启动参数
        # 可以携带 "-I" 参数到ENTRYPOINT指令中的curl
        docker run centos_curl_entrypoint -I
        >> HTTP/1.1 405 Method Not Allowed
        >> date: Mon, 05 Aug 2024 06:07:06 GMT
        >> content-type: text/plain; charset=utf-8
        >> ...
        # "pwd" 作为ENTRYPOINT指令的参数,无法被识别(curl没有pwd参数项)
        docker run centos_curl_entrypoint pwd
        >> 39.99.253.666
        
  • ARGENV 环境变量设置
    • 基本定义与使用

      # 环境变量的定义
      ENV NAME="FengLing"
      ENV AGE="18"
      ENV MYSQL_VERSION=5.6
      
      # 通过 $NAME 就可以直接获取变量值了,维护dockerfile脚本时更友好方便
      # ADD COPY EXPOSE指令同理
      RUN yum install mysql-$MYSQL_VERSION
      
    • ARGENV 区别

      ARG 仅用于构建镜像时使用, 在运行的容器中无效
      ENV 无论是在构建镜像时,还是在容器运行时,该变量都可以使用
      
  • VOLUME 设置卷
    • 在容器中进行数据挂载的两种方式

      1. 通过docker run -v参数,直接在启动容器时设置需要映射挂载的目录
      2. 构建镜像时,通过dockerfile,指定VOLUME目录
      
    • 基本介绍

      容器在运行时,应该保证在存储层不写入任何数据,运行在容器内产生的数据,我们推荐是挂载,写入到宿主机上,进行维护。
      
    • 操作演练

      # 在容器运行时,将容器内的 "/data" 文件夹自动挂载为匿名卷(存储在宿主机生成的文件目录中),任何向该目录中写入数据的操作,都不会被容器记录,保证的容器存储层无状态理念
      VOLUME /data
      
      # Dockerfile 创建镜像;运行该镜像的容器时候,这2个目录自动和宿主机的目录做好映射关系
      FROM centos:7.8.2003
      MAINTAINER fengling
      VOLUME ["/data1", "/data2"]
      
      # 可以通过 "docker image inspect 镜像id" 指令查看目录挂载情况
      
  • EXPOSE 对外的端口
    # 声明容器运行时对外提供的端口服务,帮助使用该镜像的人,快速理解该容器的一个端口业务
    # 注意: EXPOSE 指令仅仅是一个声明,它并不会实际打开或映射端口。它的主要作用是为使用者提供关于容器所使用端口的信息,并在与 docker run 命令结合使用时,作为提示和文档说明。要真正将端口暴露给主机或其他网络,还需要在运行容器时使用 -p 或 -P 选项进行端口映射
    EXPOSE 80
    EXPOSE 8080 8081
    
  • WORKDIR 设置当前工作目录
    # 当 WORKDIR 指令被执行后,后续的 RUN、CMD 和 ENTRYPOINT 指令都会在指定的工作目录中执行。如果指定的目录不存在,Docker 会自动创建它。
    # 你可以在 Dockerfile 中多次使用 WORKDIR 指令,每次使用都会更改工作目录。
    FROM ubuntu:latest
    WORKDIR /opt
    RUN mkdir myapp
    WORKDIR myapp
    COPY..
    RUN make install
    CMD ["./myapp"]
    
  • USER 指定用户
    # USER 指定用于指定运行容器内进程的用户。
    # 语法
    USER <user>[:<group>]
    # 示例
    USER root
    USER nobody
    USER daemon:daemon
    

DockerFile 实践操作

【实操一】:需求,通过dockerfile 构建 nginx 镜像,且运行容器后; 生成的页面是 "Learn the docker from me"

  • 创建 Dockerfile (文件名不可修改)
    mkdir learn_docker
    cd learn_docker
    vim Dockerfile
    
  • 编辑 Dockerfile
    # 指定基础镜像
    FROM nginx
    # 修改nginx默认的欢迎首页
    RUN echo '<meta charset=utf8>Learn the docker from me.' > /usr/share/nginx/html/index.html
    
  • 构建与使用镜像
    # 构建镜像
    docker build .
    
    # 查看创建好的镜像(我们这里镜像的id为b548e712b7fe)
    docker images
    >> REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
    >> <none>       <none>    b548e712b7fe   57 seconds ago   141MB
    
    # 修改镜像名字
    docker tag b548e712b7fe my_nginx
    
    # 查看修改后的镜像
    docker images
    >> REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
    >> my_nginx     latest    b548e712b7fe   9 minutes ago   141MB
    
    # 运行镜像
    docker run -d -p 80:80 my_nginx
    
    # http访问测试(页面显示结果为: Learn the docker from me.)
    http://39.99.253.666/
    

附录一: Docker 常用指令

一、Docker 基本指令

# docker版本
docker version

# CentOS系统docker 启动/停止/重启
sudo systemctl start docker
sudo systemctl stop docker
sudo systemctl restart docker
# Ubuntu系统docker 启动/停止/重启
sudo service docker start
sudo service docker stop
sudo service docker restart

# 退出docker
exit

# docker信息
docker info
# docker数据存放目录
docker info | grep Root
# 查看指定容器的端口映射信息
docker port <容器ID 或 容器名称>

二、镜像操作指令

# 查找镜像
docker search <镜像名称>:<标签>
docker search nginx

# 拉取镜像
docker pull <镜像名称>:<标签>
docker image pull library/hello-world 
# 由于 Docker 官方提供的 image 文件,都放在library组里面,所以它的是默认组,可以省略
docker pull hello-world
docker pull centos:7.8.2003
docker image pull hello-world 
# 删除镜像
docker image rm <镜像名或镜像id>
docker rmi <镜像名或镜像id>
# 删除多个镜像(慎用) `docker images -aq` 表示列出所有镜像id
docker rmi `docker images -aq`

# 查看本地镜像(-q只列出镜像的id)
docker images
docker image ls
# 格式化显示镜像 --format "{{.选项名称}}" table以表格形式显示
docker images --format "{{.ID}}: {{.Repository}}"
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t"
# 查看本地指定名称的镜像
docker images <镜像名称>
docker images ubuntu
# 查看镜像的详细信息
docker image inspect 镜像id(可以是id前几位)
docker image inspect 605

# 保存镜像(镜像备份,将镜像打包成文件)
docker save -o <保存的文件名> <镜像名称>:<标签>
docker save -o ./ubuntu.tar ubuntu:18.0.2003
# 加载镜像(镜像迁移,将镜像加载到本地)
docker load -i <保存的文件名>
docker load -i ./ubuntu.tar

三、容器操作指令

# 创建并启动容器 (如果镜像不存在本地,则会在线去下载该镜像)
docker run [option] <镜像名称>:<标签> [向启动容器中传入的命令]
# 创建一个交互式容器,并命名为myubuntu
docker run --name=myubuntu -it ubuntu bash
docker run --name=myubuntu  -d -p 80:80 nginx
参数说明:
  -i 表示以“交互模式”运行容器
  -t 表示容器启动后会进入其命令行。加入这两个参数后,容器创建就能登录进去。即 分配一个伪终端。
  -v 表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录,即 宿主机目录:容器中目录),可以使 用多个-v 做多个目录或文件映射。注意:最好做目录映射,在宿主机上做修改,然后 共享到容器上。
  -d 在run后面加上-d参数,则会创建一个守护式容器在后台运行(这样创建容器后不会自动进入容器,如果只加 "-i -t" 两个参数,创建后就会自动进入容器)。
  -p 表示端口映射,宿主机port:容器port。可以使用多个-p 做多个端口映射; 
  -P 随机端口映射,随机访问一个宿主机的空闲端口,映射到容器内打开的端口
  -e 为容器设置环境变量
  --name='容器名' 为创建的容器命名
  --network=host 表示将主机的网络环境映射到容器中,容器的网络与主机相同
  --restart=always 容器开机自启动
  --rm 退出容器时删除该容器,一般调试容器时添加,避免创建很多不需要的容器
  
# 查看正在运行的容器
docker container ls
docker ps
# 查看所有容器(包括已停止的)
docker container ls --all
docker ps -a

# 启动已停止的容器
docker container start <容器ID 或 容器名称>
docker start <容器ID 或 容器名称>
# 重启容器
docker container restart <容器ID 或 容器名称>
docker restart <容器ID 或 容器名称>

# 停止容器
docker container stop <容器ID 或 容器名称>
docker stop <容器ID 或 容器名称>
# 强制终止容器
docker container kill <容器ID 或 容器名称>

# 删除容器 -f 强制删除容器
docker container rm <容器ID 或 容器名称>
docker rm <容器ID 或 容器名称>
docker rm -f <容器ID 或 容器名称>
# 删除多个容器(慎用) `docker ps -aq` 表示列出所有容器id
docker rmi `docker ps -aq`

# 进入正在运行的容器
docker exec -it <容器ID 或 容器名称> <要执行的命令>
docker exec -it ubunu bash

# 查看容器内资源
docker stats <容器ID 或 容器名称>
# 查看容器的日志
docker logs <容器ID 或 容器名称>
# 实时监控容器的运行状况和输出信息
docker logs -f <容器ID 或 容器名称>
# tail -5 只显示输出的最后 5 行内容
docker logs <容器ID 或 容器名称> | tail -5
# 查看容器的详细信息
docker container inspect 镜像id(可以是id前几位)
docker container inspect 605
# 格式化显示容器信息 --format "{{.选项名称}}" table以表格形式显示
docker inspect --format "{{.ID}}: {{.Repository}}" <容器ID 或 容器名称>

# 基于一个已存在的容器创建一个新的镜像(镜像名一般格式为: dockerhub账号/镜像名:版本号)
# docker commit 并不是一种推荐的创建 Docker 镜像的最佳实践。因为它可能会包含一些不必要的文件和配置,而且难以追踪和复现镜像的创建过程。通常更推荐使用 Dockerfile 来定义镜像的构建过程,这样更加清晰、可维护和可重复
docker commit <容器ID 或 容器名称> <镜像名>
docker commit 2e080d74fbe1 fengling/centos-vim-7.8.2003
  • 容器运行的注意事项

    • 容器内的进程必须处于前台运行状态,否则容器就会直接退出,自己部署一个容器运行,命令不得后台运行,前台运行即可
    • 如果容器内,什么事也没做,容器也会挂掉; 容器内,必须有一个进程在前台运行,例如:我们运行nginx基础镜像,没有运行任何程序,因此容器直接挂掉
  • docker savedocker commit 的区别

    • 用途

      docker save 主要用于将一个或多个镜像保存为一个归档文件(通常是 .tar 格式),以便在其他环境中进行迁移或备份。
      docker commit 用于基于一个正在运行的容器创建一个新的镜像。
      
    • 操作对象

      docker save 针对的是整个镜像。
      docker commit 基于运行中的容器。
      
    • 容器的更改

      docker save 它保存的是原始的镜像,不包含在容器运行过程中所做的任何数据修改。
      docker commit 可以将容器中所做的修改(如安装新的软件、修改配置文件等)提交为一个新的镜像。假设你启动了一个容器,并在其中进行了一些配置和安装操作,然后希望将这些更改保存为一个新的镜像,以便后续基于这个新镜像创建新的容器,此时就可以使用 docker commit 命令。
      
    • 总结

      docker save 侧重于对已有镜像的备份和迁移,而 docker commit 则侧重于基于容器的更改创建新的镜像
      

附录二: 其他常用指令

# 查看外网IP地址(Ubuntu/Centos/Win 通用)
curl ifconfig.me
curl cip.cc
# 查看操作系统发行版本,适用于多种不同的 Linux 发行版
cat /etc/os-release
posted @ 2024-08-05 22:45  CSMrDong  阅读(27)  评论(0编辑  收藏  举报