【测试开发学习历程】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 指定的文件
相关推荐
StickToForever17 分钟前
第4章 信息系统架构(五)
经验分享·笔记·学习·职场和发展
Bright16684 小时前
centos9安装k8s集群
云原生·容器·kubernetes
leegong231114 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql
Moonnnn.4 小时前
51单片机学习——动态数码管显示
笔记·嵌入式硬件·学习·51单片机
南宫生5 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
!!!5255 小时前
华为云镜像加速器
docker·容器·华为云
技术小齐5 小时前
网络运维学习笔记 016网工初级(HCIA-Datacom与CCNA-EI)PPP点对点协议和PPPoE以太网上的点对点协议(此处只讲华为)
运维·网络·学习
竹言笙熙5 小时前
代码审计初探
学习·web安全
日记成书6 小时前
物联网智能项目
物联网·学习
虾球xz6 小时前
游戏引擎学习第118天
学习·游戏引擎