【测试开发学习历程】Docker入门

前言

Linux命令到上一篇博文就可以告一个段落了哦 ~ ~

今天初步学习在测试中很重要的东西:Docker

目录

[1 Docker概述](#1 Docker概述)

[1.1 Docker产生的背景?](#1.1 Docker产生的背景?)

[1.2 Docker的理念?](#1.2 Docker的理念?)

[1.3 Docker的优势](#1.3 Docker的优势)

[1.3.1 传统的虚拟机](#1.3.1 传统的虚拟机)

[1.3.2 容器化虚拟技术:](#1.3.2 容器化虚拟技术:)

[1.4 镜像](#1.4 镜像)

[1.5 容器](#1.5 容器)

[1.6 仓库](#1.6 仓库)

[2 image镜像](#2 image镜像)

[3 container容器](#3 container容器)

[4 repository仓库](#4 repository仓库)

[5 拓展](#5 拓展)

[5.1 镜像的原理](#5.1 镜像的原理)

[5.2 Docker镜像加载原理](#5.2 Docker镜像加载原理)

[5.3 为什么docker采用这种分层的原理呢?](#5.3 为什么docker采用这种分层的原理呢?)

[5.4 镜像的特点?](#5.4 镜像的特点?)

[6 一些问题解惑?](#6 一些问题解惑?)

[7 Dockerfile的体系结构](#7 Dockerfile的体系结构)

[7.1 from](#7.1 from)

[7.2 maintainer](#7.2 maintainer)

[7.3 run](#7.3 run)

[7.4 cmd](#7.4 cmd)

[7.5 entrypoint](#7.5 entrypoint)

[7.6 expose](#7.6 expose)

[7.7 env](#7.7 env)

[7.8 copy](#7.8 copy)

[7.9 add](#7.9 add)

[7.10 volume](#7.10 volume)

[7.11 user](#7.11 user)

[7.12 workdir](#7.12 workdir)

[7.13 onbuild](#7.13 onbuild)

[7.14 healthcheck](#7.14 healthcheck)


1 Docker概述

1.1 Docker产生的背景?

开发自测完成后,交给运维部署;

但是,运维部署的环境部署出来有问题;

开发说我自己的环境是对的,这个时候就有冲突了;

同时,可能不止是一个环境部署有问题,可能还有其他环境,比如TEST 环境、UAT环境、PRO环境,集群就更老火了......

开发、运维、测试都崩溃......

这就成为了一个痛点 为什么有问题呢?

  • 环境差异
  • 应用配置文件有差异......

于是,软件带环境安装,就产生了docker

  • 一套包含了开发人员所有的原始环境(代码、运行环境、依赖库、配置文 件、数据文件等)
  • 那么我就可以在任何环境上直接运行 以前部署项目的代码叫搬家,现在直接就是搬整栋楼;
  • 以前只买鱼,现在 把鱼缸那些一套全买了;

1.2 Docker的理念?

一次编译,到处运行,不依赖于环境了;

Docker是基于Go语言实现的云开源项目;

Docker的主要目标是"Build,Ship and Run Any App,Anywhere", 也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使 用户的App(可以是一个web应用或者数据库应用等等)及其运行环境能够 做到"一次封装,到处运行";

  • build,构建
  • ship,传输
  • run,运行

总结,什么是docker?

docker就是解决了运行环境和配置问题的软件容器,方便持续集成并有 助于整体发布的容器化虚拟技术。

1.3 Docker的优势

1.3.1 传统的虚拟机

如:vmware workstation,virtual box,virtual pc

  • 可以在一个操作系统中运行另一种操作系统
  • 模拟的是包括一整套操作系统

特点:

  • 启动慢,分钟级的
  • 资源占用多
  • 冗余步骤多
  • 有Hypervisor硬件资源虚拟化

1.3.2 容器化虚拟技术:

docker就去掉了Hypervisor硬件资源虚拟化,换成了Docker Engine

那么运行在docker容器上的程序直接使用的都是实际物理机的硬件资源

因此在cpu、内存利用率上docker将会有明显上的效率优势

LXC, Linux Containers

  • 模拟的不是一个完整的操作系统
  • 只需要精华版、缩小版、浓缩版的的小型的操作系统
    • centos/ubuntu基础镜像仅200M不到,iso文件多大(4个多G 吧)
    • 容器与虚拟机不同,不需要捆绑一整套操作系统
    • 只需要软件所需的库资源和设置
    • 因此变得轻量级,并且能保证在任何环境中的软件都能始终如 一地运行

docker启动秒级的:

  • docker利用的是宿主机的内核,而不需要Guest OS;
  • 因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一 个操作系统内核;
  • 从而避免了引导、加载操作系统内核这个比较费时费资源的过程;
  • 当新建一个虚拟机时,虚拟机软件需要加载Guest OS,这个新建过程是分钟级别的;
  • 而docker由于直接利用宿主机的操作系统,则省略了这个过程,因此新建一个docker容器只需要几秒钟;

容器内的应用进程直接运行于 宿主机的内核

  • 容器没有自己的内核,而且也没有进行硬件虚拟
  • 因此容器要比传统的虚拟机更为轻便

每个容器之间互相隔离

  • 每个容器有自己的文件系统
  • 容器之间进程不会相互影响
  • 能区分计算资源

宿主机可以部署100~1000个容器,你这个传统的虚拟化能行?

性能,尤其是IO和内存的消耗低

轻量

  • 基于容器的虚拟化,仅包含业务运行的所需的Runtime环境

高效

  • 无操作系统虚拟化的开销
    • 计算:轻量,无额外开销
    • 存储:系统盘aufs/dm/overlayfs;数据盘volume
    • 网络;宿主机网络,NS隔离

更敏捷、更灵活

  • 分层的存储和包管理,devops理念
  • 支持多种网络配置

1.4 镜像(重点)

镜像就是软件 + 运行环境的一整套

镜像可能包括什么?

  • 代码
  • 运行的操作系统发行版
  • 各种配置
  • 数据文件
  • 运行文档
  • 运行依赖包
  • ......

镜像就是模板

1.5 容器(重点)

容器就是镜像的运行实例

  • 容器可以有多个,均来自于同一个镜像,镜像是一个只读的模板

容器就是集装箱

  • 容器就是运行着的一个个独立的环境,独立的软件服务
  • 容器都是相互隔离、保证安全的平台

容器也可以看做一个简易版的linux环境

  • 包括root用户权限、进程空间、用户空间和网络空间等
  • 和运行在其中的应用程序

1.6 仓库(重点)

存放镜像的地方

仓库【Repository】是集中存放镜像文件的场所

仓库注册服务器【Registry】,仓库注册服务器上存放着多个仓库

  • 每个仓库中又包含了多个镜像
  • 每个镜像有不同的标签Tag

仓库有公开仓库【public】和私有仓库【private】两种形式

  • 最大的公开仓库:Docker Hub
    • 国内的公开仓库有:阿里云、网易云等
  • 私有仓库,一般自己公司搭建的
    • 一般也是运维搭建,测试不用管

鲸鱼背上有集装箱

  • 鲸鱼:docker
  • 集装箱:容器实例 ---> 来自镜像
  • 大海:宿主机操作系统

容器才可以提供服务 -- 需要通过镜像来运行容器 -- 从仓库获取镜像

2 image镜像

|----------------------------------|------------------|
| docker image ls | 列出本机的镜像 |
| docker rmi 镜像ID | 删除镜像,可接多个ID |
| docker rmi 仓库名:TAG | 删除镜像,可接多个仓库名:TAG |
| docker pull 仓库名:TAG | 拉取镜像 |
| docker search 仓库名 | 搜索docker hub上的仓库 |
| docker image inspect 镜像id | 查看镜像详情 |
| docker image inspect 仓库名:TAG | 查看镜像详情 |
| docker save -o XXX.tar 镜像:tag | 导出镜像 |
| docker [image] load -i XXX.tar | 导入镜像 |
| docker tag 镜像id 别名 | 对镜像起别名,会生成一个新的镜像 |

下面命令可以不用那么熟练:

  • docker image ls -qa, 只查询出镜像的id
  • docker rmi -f $(docker image ls -qa),强制删除所有的镜像
  • docker rmi -f `docker images -qa`,也是强制删除所有的镜像
  • docker image ls --digests, 附带查看digests信息
  • docker image ls --no-trunc,镜像id全部展示,不截断

3 container容器

docker run xxx

  • -d 后台运行
  • --name 自己起的容器名称,名字不能冲突,如果不指定,系统自动给你随机分配一个名字
  • -p 本宿主机端口:容器端口,端口不能重复调用,比如 -p 3307:3306 是把容器的3306端口映射到本机的3307端口
  • -P 随机端口号,系统分配,访问的时候,用docker ps 查看端口号,然后通过ip:端口号访问
  • -i 交互式 -i, --interactive Keep STDIN open even if not attached
  • -t 终端 -t, --tty Allocate a pseudo-TTY
  • -v 宿主机目录:容器内部目录
    • -v /tomcat/data:/usr/local/tomcat/webapps 挂载数据卷,将 tomcat的部署的目录(/usr/local/tomcat/webapps)挂载到自定义的挂载卷 (/tomcat/data)上面去;
    • -v /tomcat/conf:/usr/local/tomcat/conf 挂载数据卷,将 tomcat的配置文件路径(/usr/local/tomcat/conf )挂载到本机定义的挂载卷(/tomcat/conf)上面去,以后启动别的容器,就可以重用这个conf配置;
    • tomcat:8.0-jre8 启动的tomcat的镜像名称;
    • 数据卷的作用?
      • 持久化容器的数据
      • 容器间共享数据

docker run hello-world 启动一个镜像为hello-world的容器

docker ps 查看正在运行的容器

  • docker run hello-world
  • 运行容器,就是要用run命令
  • hello-world 没有接TAG,就表示要使用latest版本
  • 会提示你找不到这个镜像
  • 会自动给你下载这个hello-world的最新版本latest的镜像

docker ps -a 查看所有容器,包括运行的和没有运行的

  • 删除已停止的容器:docker rm ID(可连续跟)
  • 查看已停止的容器:docker ps -f status=exited

docker ps -q 查看容器的id,静默显示

docker ps -qa 查看所有容器的id,包括已停止的

docker run --name mycentos centos 运行容器,--name xxx表示给这个容器起个名字

docker run -it centos 交互式运行容器,并进入容器,-i交互式的,-t给分配一个伪终端

  • exit 退出容器,但是出来后容器就被关闭了
  • ctrl + P + Q 退出容器,但是不关闭容器
  • 容器不存在

docker stop 容器名称 # 停止容器,这种是缓慢的停止

  • docker stop 容器ID # 也是可以的

docker start centos 启动容器

docker restart centos 重启容器

docker kill centos 停止容器,粗暴的停止

docker inspect mycentos 查看容器的详细信息

docker exec -it c1 /bin/bash 可进入到容器(c1 表示容器)

  • 进入之后,可以进行自定义的修改,比如修改tomcat主页
  • exit
  • ctrl + P+Q 退出终端,而不关闭容器
  • 容器已经启动(up)

提交镜像

a(auther) m(message)

docker commit -a '作者' -m '注释信息' 容器名/容器ID 自己要起什么名[仓库名:TAG]

  • 提交新的镜像:docker commit -a 'lanhai' -m 'comment, update tomcat index page' tomcat1 tomcat:test1_v1.0.1;
  • 然后就可以使用新的镜像docker run -d -p 8086:8080 --name tomcat3 tomcat:test1_v1.0.1;
  • 使用场景,你如果在一个容器内了做了一些修改配置,然后以后也想用这样的配置,就可以配置;

docker run -d --name c1 centos 后台启动容器

docker logs c1 查看日志

docker logs -f c1 实时查看日志

docker logs --tail 3 c1 显示最后几行日志

docker cp 本机文件 容器名:容器的路径目录 #将本机的文件拷贝到容器内部的指定的那个目录

docker cp c1:/tmp/test.log /root/test.log 容器内拷贝出来

docker run -d -p 8888:8080 -v /root/volume_test:/container_volume --name t1 tomcat 挂载宿主机的/root/volume_test到容器的/container_volume目录

以下命令不用太过熟练:

  • docker ps -l,显示上次运行的容器
  • docker ps -n 3, 显示最近三次运行的容器

某些说明:

docker run -d centos, 为什么运行后就退出呢?

  • docker ps -a 查看,会发现容器已经退出
  • 注意:docker容器后台运行,就必须有一个前台进程
  • 容器运行的命令如果不是那些一直挂起的命令(比如top、tail等),就是会自动退出的
  • 这个是docker的机制问题,比如你的web容器,我们以nginx为例。
    • 正常情况下,我们配置启动服务只需要启动响应的service即可。例如servcie nginx start
    • 但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用
    • 这样,容器后台启动后,会立即自杀,因为它觉得它没事可做了
    • 所以,最佳的解决方式,是将你要运行的程序以前台进程的形式运行

docker run -d centos /bin/sh -c "while true;do echo hello canglaoshi $(date +'%Y-%m-%d %H:%M:%S');sleep 2;done"

  • 写个死循环,占用前台进程
  • docker logs -f 容器名, 可以查看容器的日志

docker top 容器名称, 查看容器内部的进程

docker attach 容器名称,直接进入容器

docker exec -it 容器 bash

  • docker exec -it 容器名称 /bin/bash
  • docker exec -it 容器名称 /bin/sh
  • docker exec -it 容器名称 ls -l /tmp, 可以不进入容器,直接查看容器内命令结果
  • docker exec 容器名称 ls -l /tmp,可以不进入容器,直接查看容器内ls -l /tmp命令的结果

attach 和 exec 的区别:

  • 两个命令都可以进入容器
  • attach 是直接进入之后才能干活
  • exec 也可以直接进入后干活,但是exec还能在不进入容器的情况下,运行命令

docker run -d -v xxx:yyy:ro 镜像, 挂载卷设置只读权限

表示什么呢?

  • 宿主机上挂载的那个目录可以正常写入
  • 容器内挂载的那个目录只读,【容器只能看】

--volumes-from

  • docker run -it --name centos1 lanhai:v0.0.1
  • docker run -it --name centos2 --volumes-from centos1 lanhai:v0.0.1
  • docker run -it --name centos3 --volumes-from centos1 lanhai:v0.0.1
    • 分别在centos2里面的挂载目录新建数据
    • 分别在centos3里面的挂载目录新建数据
    • 删除容器centos1,那么centos2和centos3的都在
    • 同时,任何一个挂载卷新增修改数据,都会同步
      • 所以,可以实现容器间数据共享

4 repository仓库

docker push 镜像名:TAG

5 拓展

(功利地说:低频考点)

5.1 镜像的原理

镜像的加载分层采用UnionFS联合文件系统;

UnionFS:

  • UnionFS是一种分层、轻量级并且高性能的文件系统;
  • 它支持对文件系统的修改作为一次提交来一层层的叠加;
  • 同时可以将不同目录挂载到同一个虚拟文件系统下;
  • UnionFS是Docker镜像的基础镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以只做各种具体的应用镜像;

特点:

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

5.2 Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就叫UnionFS;

  • bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,linux刚启动的时候会加载bootfs文件系统,在Docker镜像的最底层就是bootfs;
    • 这一层与我们典型的linux/unix系统是一样的,包含boot加载器和内核;
    • 当boot加载完成后,整个内核就在内存中了,此时内存的使用权已由 bootfs转交给内核,此时系统也会卸载bootfs;
  • rootfs(root file system),在bootfs之上,包含的就是典型的linux系统 中的/dev、/proc、/bin、/etc等标准目录和文件;
    • rootfs就是各种不同的操作系统发行版,比如Centos、Ubuntu等。

对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了;

因为底层直接用的HOST的kernel,自己只需要提供rootfs就行了;

由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs有差别,因此不同 的发行版可以公用bootfs;

5.3 为什么docker采用这种分层的原理呢?

最大的好处,就是资源共享

  • 比如: 有多个镜像都从相同的base镜像构建而来,那么宿主机只需要在磁盘上保存一 份base镜像就可以了
  • 同时内存中也只需加载一份base镜像,就可以为所有的容器服务了
  • 而且镜像的每一层都可以被共享
  • 比如,你同时下载了tomcat、centos、nginx、mysql等的镜像
    • 那么他们这些镜像里面可能有很多的base层镜像是一样的,那么就不用每个都去下载了
    • 只保留一份就可以了

5.4 镜像的特点?

镜像是只读的;

当镜像启动为容器后,一个新的可写层被加载到了镜像的顶部;

这一层通常被称为容器层,而容器层以下的都叫镜像层;

6 一些问题解惑?

docker run -it -p 8081:8080 --name tomcat1 tomcat:8.0-jre8 bash 像这个命令启动容器后为什么,访问不了?

分析:

  • 启动容器的时候,带了启动命令bash,那么就会tomcat的Dockerfile里面的 CMD命令给覆盖了
  • 说白了,就是这个tomcat容器启动的时候,没有启动前台命令
  • 如何解决?
    • 其实现在run -it的方式已经进入了容器,那么可以手动启动tomcat的 脚本,就能访问了
    • cd /usr/local/tomcat/bin
    • ./startup.sh
    • 再次访问,ok

7 Dockerfile的体系结构

7.1 from

FROM 镜像 指定新镜像所基于的镜像,第一条指令必须为FROM指令,每创建一个镜像就需 要一个FROM指令;

7.2 maintainer

MAINTAINER 名字 说明镜像的维护人员信息;

7.3 run

RUN 命令 在所基于的镜像上执行命令,并提交到新的镜像中;

7.4 cmd

CMD ["要运行的程序", "参数1", "参数2"] 指定启动容器时要运行的命令或者脚本

只能有一条CMD命令,如果有多条,那么只有最后一条生效,前面的都被覆盖了

启动容器时,如果启动命令带了参数,那么这个参数会将cmd中的配置给替换

7.5 entrypoint

ENTRYPOINT ["要运行的程序", "参数1", "参数2"] 指定启动容器时要运行的命令或者脚本

启动容器时,如果docker run启动命令带了参数,那么这个参数会被追加为参数,然后形成新的命令组合

7.6 expose

EXPOSE 端口号 指定新镜像加载到docker时要被开启的端口

7.7 env

ENV 环境变量 变量值 设定一个环境变量,会被后面的命令所使用,如RUN,如WORKDIR

7.8 copy

COPY 源文件/目录 目标文件/目录 将本地主机上的东西,复制到目标地址,这个本地主机上的"源文件/目录"必须要与Dockerfile在同一个目录;

7.9 add

ADD 源文件/目录 目标文件/目录

同copy命令,但是多一个能解压tar包的功能,以及能自动处理URL

7.10 volume

VOLUME 目录

在容器中创建一个挂载目录

7.11 user

USER username/UID 指定运行容器的用户

7.12 workdir

WORKDIR 路径

为后续的RUN,CMD,ENTRYPOINT指定工作目录

7.13 onbuild

ONBUILD 命令

指定这个镜像被作为基础镜像继承时,所要运行的命令,相当于一个触发器

  • 别的镜像继承我这个镜像【这个Dockerfile里面写了onbuild】的时候,在构建的时 候,会触发父镜像的这个onbuild的执行
  • Father 镜像的Dockerfile
    • 里面包含了onbuild
  • Son ---> FROM Father
    • build构建的时候,会执行Father镜像里面的onbuild语句
  • eg. ONBUILD run echo "hello onbuild test....."

7.14 healthcheck

HEALTHCHECK 健康检查

命令: docker build . -t xxx:v0.0.1 -f /root/xxx/Dockerfile

  • -f 指定的文件
相关推荐
南宫生26 分钟前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
武子康2 小时前
大数据-212 数据挖掘 机器学习理论 - 无监督学习算法 KMeans 基本原理 簇内误差平方和
大数据·人工智能·学习·算法·机器学习·数据挖掘
使者大牙2 小时前
【大语言模型学习笔记】第一篇:LLM大规模语言模型介绍
笔记·学习·语言模型
As977_2 小时前
前端学习Day12 CSS盒子的定位(相对定位篇“附练习”)
前端·css·学习
ajsbxi2 小时前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
Rattenking2 小时前
React 源码学习01 ---- React.Children.map 的实现与应用
javascript·学习·react.js
景天科技苑2 小时前
【云原生开发】K8S多集群资源管理平台架构设计
云原生·容器·kubernetes·k8s·云原生开发·k8s管理系统
dsywws2 小时前
Linux学习笔记之时间日期和查找和解压缩指令
linux·笔记·学习
道法自然04023 小时前
Ethernet 系列(8)-- 基础学习::ARP
网络·学习·智能路由器
爱吃生蚝的于勒3 小时前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法