可可爱爱集装箱-docker

171 阅读13分钟

我正在参加「掘金·启航计划」

前端或者后端攻城狮可能听过docker这个神奇的东东 今天来浅浅的进行docker的简单概述

内容提示:基础简介与命令使用

Docker简介

什么是Docker

Docker 使用 Go 语言开发实现 基于Linux 内核的 cgroup namespace 以及 OverlayFS类的UnionFS等技术 对进程进行封装隔离 属于操作系统层面的虚拟化技术

Docker在容器的基础上 进行了进一步封装 传统虚拟机:虚拟出一套硬件 在其上运行一个完整操作系统 容器:容器内应用直接运行与宿主的内核 容器没有自己的内核 没有进行硬件虚拟

为什么要用Docker

  • 更高效的利用系统资源

不需要进行硬件虚拟以及运行完整操作系统开销

  • 更快速启动

直接运行宿主内核 无需启动完整的操作系统

  • 一致的运行环境

Docker 镜像提供了除内核外完整的运行时环境 确保了应用运行环境一致性

  • 持续交付和部署

Devops 定制镜像 持续集成 持续部署 使用DockerFile使镜像构建透明化

  • 更轻松的迁移

确保了执行环境的一致性 使得应用迁移更容易

  • 更轻松的维护和拓展

分层存储 镜像技术 官方镜像 :可以直接在开发模式使用 也可以定制

特性容器虚拟机
启动秒级分钟级
硬盘使用一般为MB一般为GB
性能接近原生弱于
系统支持量单机支持上千容器一般几十个

基本概念

镜像 Image

操作系统分为内核和用户空间 Linux内核启动之后会挂在root文件系统为用户空间支持

Docker镜像相当于一个root文件系统 不包含任何动态数据

分层存储

镜像包含操作系统完整的root文件系统 体积是庞大的 利用Union FS 的技术 由一组文件系统组成 一层一层构建 使复用 定制更为容易

容器

面向对象中的类与实例 镜像是静态的定义 容器时镜像运行实体

容器的实质是进程 拥有自己独立的命名空间 文件系统 网络配置 用户id 进程空间都是隔离的

容器存储层的生命周期和容器一样 容器消亡之后 容器存储层随之消亡 任何保存于容器存储层的信息都会随容器删除而丢失

Docker最佳实践:容器存储层要保持无状态化 所有的文件写入操作 应该使用数据卷或者绑定宿主目录

仓库

要在其他服务器上使用镜像 就需要一个集中的存储分发镜像的服务 Dokcer Registry就是这样的服务

包含多个仓库 与标签 一个标签对应一个镜像

通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

Docker Registry 公开服务

官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的 官方镜像。除此以外,还有 Red Hat 的 Quay.io;Google 的 Google Container Registry,Kubernetes 的镜像使用的就是这个服务;代码托管平台 GitHub 推出的 ghcr.io。

私有 Docker Registry

除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务

使用镜像

获取镜像

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

镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 sha256 的摘要,以确保下载一致性。

运行

docker run -it --rm ubuntu:18.04 bash
  • -it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
  • --rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。
  • ubuntu :18.04 :这是指用ubuntu:18.04 镜像为基础来启动容器。
  • bash:放在镜像名后的是 命令,这里我们希望有个交互式 Shell,因此用的是 bash。

列出镜像

docker image ls

镜像体积

DockerHub显示的是压缩后体积 由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 none 的镜像。这类无标签镜像也被称为 虚悬镜像(dangling image) ,可以用下面的命令专门显示这类镜像

# 显示
docker image ls -f dangling = true
# 删除
docker image prune

悬浮镜像

镜像既没有仓库名,也没有标签,均为 none。

中间层镜像

docker image ls -a 

只要删除那些依赖它们的镜像后,这些依赖的中间层镜像也会被连带删除。

列出部分镜像

docker image ls ubuntu
docker image ls ubuntu:18.04
docker image ls -f since=mongo:3.2

特定格式显示

docker image ls --format "{{.ID}}: {{.Repository}}"
docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"

删除镜像

docker image rm [选项] <镜像1> [<镜像2> ...]
docker image rm 501
docker image rm centos
docker image ls --digests
docker image rm node@sha256:b4f

Untagged 和 Deleted

当我们使用上面命令删除镜像的时候,实际上是在要求删除某个标签的镜像

是将满足我们要求的所有镜像标签都取消,这就是我们看到的 Untagged 的信息。

当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。

用docker image ls 命令来配合

docker image rm $(docker image ls -q redis)
docker image rm $(docker image ls -q -f before=mongo:3.2)

使用Dockerfile定制镜像

镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。

FROM指定基础镜像

RUN执行命令

RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

# 错误写法 (创建了七层镜像 很多运行时不需要的东西也被装进了镜像)
FROM debian:stretch

RUN apt-get update
RUN apt-get install -y gcc libc6-dev make wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install

# 正确写法
FROM debian:stretch

RUN set -x; buildDeps='gcc libc6-dev make wget' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

docker build 构建镜像

操作容器

启动

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(exited)的容器重新启动。 因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。

新建并启动

$ docker run ubuntu:18.04 /bin/echo 'Hello world'
Hello world

//-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, 
//-i 则让容器的标准输入保持打开。
$ docker run -t -i ubuntu:18.04 /bin/bash
root@af8bae53bdd3:/#

当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:

  • 检查本地是否存在指定的镜像,不存在就从 registry 下载
  • 利用镜像创建并启动一个容器
  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
  • 从地址池配置一个 ip 地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被终止

启动已终止容器

docker container start

守护态运行

docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"

docker container ls

docker container logs [container ID or NAMES]

终止

docker container stop
docker container restart

进入容器

//如果从这个 stdin 中 exit,会导致容器的停止。
docker attach 243c


docker exec -i 69d1 bash
ls
bin
boot
dev
...

docker exec -it 69d1 bash
root@69d137adef7a:/#

导出和导入

//导出
docker export 7691a814370e > ubuntu.tar
//导入
cat ubuntu.tar | docker import - test/ubuntu:v1.0
docker import http://example.com/exampleimage.tgz example/imagerepo

删除

//删除处于终止状态的容器
docker container rm
//清理所有处于终止状态的容器
docker container prune

数据管理

file 介绍如何在Docker内部以及容器之间管理数据 在容器中管理数据主要有两种方式

  • 数据卷 Volumes
  • 挂载主机目录 Bind mounts

数据卷

数据卷是一个可供一个或多个容器使用的特殊目录

  • 数据卷在容器之间共享和重用

  • 对数据卷的修改会立马生效

  • 对数据卷的更新不会影响镜像

  • 数据卷会一直存在即使容器被删除

创建一个数据卷

docker volume create my-vol
docker volume ls
//查看指定数据卷信息
docker volume inspect my-vol

启动一个挂在数据卷的容器

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

查看数据卷具体信息

//查看web容器信息
docker inspect web

删除数据卷

docker volume rm my-vol

挂载主机目录

加载主机的 /src/webapp 目录到容器的 /usr/share/nginx/html目录 Docker 挂载主机目录的默认权限是 读写,用户也可以通过增加 readonly 指定为 只读。

docker run -d -P \
    --name web \
    # -v /src/webapp:/usr/share/nginx/html \
    --mount type=bind,source=/src/webapp,target=/usr/share/nginx/html \
    nginx:alpine

使用网络

外部访问容器

容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。 当使用 -P 标记时,Docker 会随机映射一个端口到内部容器开放的网络端口。

-p 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort。

docker run -d -p 80:80 nginx:alpine
docker run -d -p 127.0.0.1:80:80 nginx:alpine
//绑定任意端口 自动分配
docker run -d -p 127.0.0.1::80 nginx:alpine
//udp
docker run -d -p 127.0.0.1:80:80/udp nginx:alpine

查看映射端口配置

docker port
docker port fa 80
0.0.0.0:32768
//绑定多个端口
docker run -d \
    -p 80:80 \
    -p 443:443 \
    nginx:alpine

容器互联

新建网络

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

docker container ls

# ping busybox2
PING busybox2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms

Docker Compose

多容器互联 建议使用 Docker Compose

配置DNS

挂载相关文件

Docker Compose

Docker Compose 是 Docker 官方编排项目之一 负责快速的部署分布式应用

简介

Compose 定位是 定义和运行多个Docker容器的应用

使用Dokcerfile模板文件 可以让用户很方便的定义一个单独的容器应用

Compose 恰好满足了这样的需求。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。

Compose 重要概念

  • 服务 一个运行的容器 实际上可以包括若干运行相同镜像的容器实例

  • 项目 由一组关联的应用容器组成的一个完整业务单元 在 docker-compose.yml中定义 Compose默认管理对象是项目 通过子命令对容器中一组容器进行便捷的生命周期管理

使用

DockerFile

FROM python:3.6-alpine
ADD . /code
WORKDIR /code
RUN pip install redis flask
CMD ["python", "app.py"]

docker-compose.yml

version: '3'
services:

  web:
    build: .
    ports:
     - "5000:5000"

  redis:
    image: "redis:alpine"

运行

docker-compose up

命令说明

命令选项

  • -f, --file FILE 指定使用的 Compose 模板文件,默认为 docker-compose.yml,可以多次指定。
  • -p, --project-name NAME 指定项目名称,默认将使用所在目录名称作为项目名。
  • --verbose 输出更多调试信息。
  • -v, --version 打印版本并退出。

命令使用说明

docker-compose build [options] [SERVICE...]

构建(重新构建)项目中的服务容器。

config 验证 Compose 文件格式是否正确,若正确则显示配置,若格式错误显示错误原因。

down 此命令将会停止 up 命令所启动的容器,并移除网络

exec 进入指定的容器。

help 获得一个命令的帮助。

images 列出 Compose 文件中包含的镜像。

kill 格式为 docker-compose kill [options] [SERVICE...]。

通过发送 SIGKILL 信号来强制停止服务容器。 支持通过 -s 参数来指定发送的信号,例如通过如下指令发送 SIGINT 信号。

$ docker-compose kill -s SIGINT

logs 格式为 docker-compose logs [options] [SERVICE...]。 查看服务容器的输出。默认情况下,docker-compose 将对不同的服务输出使用不同的颜色来区分。可以通过 --no-color 来关闭颜色。 该命令在调试问题的时候十分有用。

pause 暂停

port 打印端口

ps 列出容器

pull/push 拉取/推送 镜像

restart 重启服务

rm 删除

run 执行命令

up 尝试自动完成包括构建镜像 重写创建服务 启动服务 关联服务相关容器的一系列操作

  • -d 在后台运行服务容器。
  • --no-color 不使用颜色来区分不同的服务的控制台输出。
  • --no-deps 不启动服务所链接的容器。
  • --force-recreate 强制重新创建容器,不能与 --no-recreate 同时使用。
  • --no-recreate 如果容器已经存在了,则不重新创建,不能与 --force-recreate 同时使用。
  • --no-build 不自动构建缺失的服务镜像。
  • -t, --timeout TIMEOUT 停止容器时候的超时(默认为 10 秒)。

Compose模板文件

默认的模板文件名称为 docker-compose.yml,格式为 YAML 格式

version: "3"

services:
  webapp:
    image: examples/web
    ports:
      - "80:80"
    volumes:
      - "/data"

build 指定路径

devices 指定设备映射关系

depends_on 解决依赖关系

expose 暴露端口 植不映射到宿主机 只被连接服务访问

ports 暴露端口信息

secrets 存储敏感信息

volumes 数据卷挂载地址

结语

docker作为目前云原生火热的产品 为微服务部署开发带来了便利

基于虚拟化的云原生技术正在大放异彩 docker 我学定了!