docker学习笔记

1. Docker简介

go语言开发,基于Linux内核的cgroupnamespace等技术,对进程进行封装隔离。属于操作系统层面的虚拟化技术。

传统的虚拟机通过在宿主主机中运行 hypervisor 来模拟一整套完整的硬件环境,在其上运行一个完整操作系统,再在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

前者具有以下优点:

  • 更高效的系统资源利用率
  • 更快的启动时间
  • 通过Dockerfile快速进行镜像构建,更轻松的迁移和部署交付

在这里插入图片描述
在这里插入图片描述

2. 基本概念

2.1 Dokcer镜像

一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。

镜像不包含任何动态数据,其内容在构建之后也不会被改变。镜像利用Union FS技术,被设计为分层存储的架构,由多层文件系统组层,可以运行docker info查看当前Union FS 类型
在这里插入图片描述
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。分层存储的特征使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。

2.2 容器

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。

每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层。任何保存于容器存储层的信息都会随容器删除而丢失。所有的文件写入操作,都应该使用 数据卷(Volume)、或者 绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

2.3 仓库

如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,这就是Docker Registry。与git类似,一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。最常使用的 Registry 公开服务是官方的 Docker Hub。还有一些功能丰富的开源的仓库,例如 harbor

2.4 Dockerfile

Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction)表明如何构建镜像,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。每一层构建的最后一定要清理掉无关文件,避免制作出很臃肿的镜像。

主要命令包括(https://docs.docker.com/engine/reference/builder/#from):

  • FROM 就是指定 基础镜像。若不存在基础镜像,则使用FROM scratchRUN 指令是用来执行命令行命令的。

  • COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置

  • ADDCOPY类似,支持自动解压缩等功能,不支持缓存

  • CMD 指令就是用于指定默认的容器主进程的启动命令的,只能指定一个,否则后面的会覆盖前面的

    CMD <命令>
    # 或
    CMD ["可执行文件", "参数1", "参数2"...]
    
  • ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令

    CMD ["参数1", "参数2"...]
    ENTRYPOINT <命令>
    
  • ENV设置环境变量

    ENV <key> <value>
    ENV <key1>=<value1> <key2>=<value2>...代码片
    
  • ARG也是设置环境变量,但相比ENV,其设置的构建环境的环境变量,在将来容器运行时不存在。

  • VOLUME设置数据卷

    VOLUME ["<路径1>", "<路径2>"...]
    VOLUME <路径>
    
    VOLUME /data
    docker run -d -v mydata:/data xxxx
    
  • EXPOSE 暴露端口,其只是声明,并不会自动进行端口暴露,需要在运行时使用 -p <宿主端口>:<容器端口>

    EXPOSE <端口1> [<端口2>...]
    
  • WORKDIR 指定工作目录(或者称为当前目录)。每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。因此不同层间需要改变目录则需要使用该命令

    WORKDIR /a
    WORKDIR b
    WORKDIR c
    
    RUN pwd  # /a/b/c
    
  • USER 指令和 WORKDIR 用法相似,用于指定用户。

    USER <用户名>[:<用户组>]
    
  • ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

    FROM node:slim
    RUN mkdir /app
    WORKDIR /app
    ONBUILD COPY ./package.json /app
    ONBUILD RUN [ "npm", "install" ]
    ONBUILD COPY . /app/
    CMD [ "npm", "start" ]
    
  • LABEL 指令用来给镜像以键值对的形式添加一些元数据

    LABEL <key>=<value> <key>=<value> <key>=<value> ...
    

多阶段构建镜像

FROM golang:1.9-alpine as builder   # as命令为某阶段命名

RUN apk --no-cache add git

WORKDIR /go/src/github.com/go/helloworld/

RUN go get -d -v github.com/go-sql-driver/mysql

COPY app.go .

RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest as prod

RUN apk --no-cache add ca-certificates

WORKDIR /root/

COPY --from=0 /go/src/github.com/go/helloworld/app .  # 从第一个镜像中复制文件

CMD ["./app"]

单独运行某阶段

$ docker build --target builder -t username/imagename:tag .

2.5 容器网络

当 Docker 启动时,会自动在主机上创建一个 docker0 虚拟网桥( 参考1参考2),实际上是 Linux 的一个 bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。
同时,Docker 随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一个地址给 docker0 接口。比如典型的 172.17.42.1,掩码为 255.255.0.0。此后启动的容器内的网口也会自动分配一个同一网段(172.17.0.0/16)的地址。
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。
在这里插入图片描述

3. 常用命令

3.1 镜像相关

从仓库拉取镜像

docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]

列出镜像

docker image ls [仓库名[:标签]] [选项]

查看镜像、容器、数据卷占用的使用空间

docker system df

查看并消除虚悬镜像(dangling image)

docker image ls -f dangling=true
docker image prune

删除本地镜像
删除行为分为两类,一类是 Untagged,另一类是 Deleted。镜像的唯一标识是其 ID 和摘要,而一个镜像可以有多个标签。当删除指定标签镜像时,若还有别的标签指向这个镜像,则为 Untagged,此时并不会真正删除镜像。

docker image rm [选项] <镜像1> [<镜像2> ...]

在这里插入图片描述

将容器保存为镜像

docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

$ docker commit \
    --author "zjw" \
    --message "修改了默认网页" \
    webserver \
    nginx:v2

查看当前镜像内历史记录

docker history <镜像>

构建镜像
Docker 在运行时分为 Docker 引擎(也就是服务端守护进程)和客户端工具(例如命令行),客户端调用远程服务进行各种操作。当构建的时候,用户会指定构建镜像上下文的路径docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。

docker build [选项] <上下文路径/URL/->

$ docker build -t nginx:v3 .

#基于git构建
$ docker build -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world

#基于压缩包构建
$ docker build http://server/context.tar.gz

3.2 容器相关

新建容器并启动
检查本地是否存在指定的镜像,不存在就从公有仓库下载

1.利用镜像创建并启动一个容器
2.分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
3.从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
4.从地址池配置一个 ip 地址给容器
5.执行用户指定的应用程序
6.执行完毕后容器被终止

docker run -it ubuntu:18.04 /bin/bash  #获取用户交互
docker run -d ubuntu:18.04  #后台运行,输出结果使用 docker container logs查看

启动已终止的容器

docker start <name>

进入容器

docker exec -it <name> bash

查看容器列表

docker ps

终止容器

docker stop <name>

删除容器

docker rm <name> # -f 为强制停止容器并删除

查看容器详细信息

docker inspect <name>

3.3 存储相关

创建数据卷

docker volume create my-vol

查看数据卷列表

docker volume ls

查看数据卷详细信息,包括挂载点、驱动等

docker volume inspect my-vol

删除数据卷

docker volume rm my-vol

挂载数据卷

docker run -d -P \
    --mount source=my-vol,target=/usr/share/nginx/html \
    nginx:alpine

挂载主机目录

$ docker run -d -P \
    --mount type=bind,source=/src/webapp,target=/usr/share/nginx/html,readonly \
    nginx:alpine

3.4 网络相关

随机映射一个端口到内部容器开放的网络端口

docker run -d -P nginx:alpine

指定映射端口,本地 : 容器

docker run -d -p 80:80 nginx:alpine

docker run -d \
    -p 80:80 \
    -p 443:443 \
    nginx:alpine

创建docker网络

docker network create -d bridge my-net

连接容器网络

docker run -it --rm --name busybox1 --network my-net busybox sh
docker run -it --rm --name busybox2 --network my-net busybox sh

4. 底层原理

Docker 底层的核心技术包括 Linux 上的命名空间(Namespaces)、控制组(Control groups)、Union文件系统(Union file systems)和容器格式(Container format)
Docker 采用了 C/S架构,包括客户端和服务端。Docker 守护进程 (Daemon)作为服务端接受来自客户端的请求,并处理这些请求(创建、运行、分发容器)。
客户端和服务端既可以运行在一个机器上,也可通过 socket 或者 RESTful API 来进行通信。

docker通过命名空间隔离文件目录、进程、网络、user等,通过控制组隔离共享底层的资源,比如cpu、内存、磁盘IO、网络带宽等。通过Union文件系统实现镜像分层。参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值