# docker概述(百度百科)

# 什么是docker

  • 开源的应用容器引擎

# docker的组成

  1. dockerClient客户端
  2. Docker Daemon守护进程
  3. Docker Image镜像
  4. DockerContainer容器

# docker起源

  • PaaS提供商dotCloud开源的基于LXC(Linux Container)的高级容器引擎,基于go语言进行开发
    • Linux Container是一种轻量级内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源。
    • LXC当相遇c++中的NameSpace,将由单个操作系统管理的资源,划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。
  • 2013以来非常火热;
  • LXC在Linux2.6的kernel就已经存在,由于其设计之初,并非为云计算考虑,因此其构建出的环境难以迁移和标准化管理。docker在这个问题上对其进行了实质性的革新,这也是docker最独特的地方。

一款开源软件能否在商业上成功,很大程度上依赖三件事-成功的userCase(用例),活跃的社区和一个好的故事.

# docker版本发布历史

  • 2010年,dotCloud公司城里,提供一些paas的云计算服务,与LXC有关的容器技术
  • 2013年,docker开源,没有引起行业的注意,dotCloud就会活不下去
  • 2013年,发布0.0.1版本
  • 2014年8月,Docker 1.0发布
  • 2016年7月,Docker 1.8发布
  • 2019年11月,Docker 1.25发布
  • 2021年4月,Docker 1.29发布
  • 2021年9月,Docker 2.0发布
  • 2022年4月,Docker 2.5发布

# 架构

  • 使用C/S架构管理Docker镜像
  • Docker容器通过Docker镜像来创建(镜像与容器的关系类似于类与对象的关系)
  • Docker daemon作为服务端接收来自客户的请求,并处理(创建、运行、分发容器);客户端和服务端既可以运行在一个机器上,也可以通过 socket或 Restful API来进行通信;

# docker适用场景

  • 自动化部署
  • 轻量级、私密的PAAS环境
  • 实现自动化测试和持续集成/部署
  • 部署与扩展webapp,数据库和后台服务

# docker命令(菜鸟教程)

# 容器生命周期命令

# run命令

  • -i: 以交互模式运行容器,通常与 -t同时使用
  • -t: 为日供气重新分配一个伪输入端口,通常与-i同时使用
docker run --name myng -d nginx:latest   #后台模式启动nginx,并将容器命名为myng

docker run -p 80:80 -v /data:/data -d nginx:latest # 主机80端口映射到容器的80端口,主机的/data目录映射到容器的/data目录

# start/stop/restart命令

docker start myContainer #启动被停止的容器

docker stop myContainer # 停止运行中的容器

docker restart myContainer # 重启容器

# kill命令

docker kill myContainer #关闭运行中的容器

# pause/unpause

docker pause myContainer # 暂停容器中的所有进程

docker unpause myContainer # 恢复容器中的所有进程

# create命令

docker create --name myContainer nginx:lates #使用docker 镜像 nginx:latest创建一个容器,并命名为myContainer 

# exec命令

docker exec -it mynginx /bin/sh /root/myShell.sh # 在myNginx容器中,以交互模式 执行容器内 /root/myShell.sh脚本

docker exec -it mynginx /bin/bash #在容器mynginx中,开启一个交互模式的终端

docker ps -a #可查看到已经在运行的容器
docker exec -it <容器id> /bin/bash #开启一个交互式终端
docker attach <容器id> #进入已有的交互式终端

# 容器操作命令

# exec命令

docker ps 
#对正在执行的容器追加控制台命令
docker exec -it <容器ID或名称> /bin/sh

# ps命令

docker ps -a # 列出所有容器,包括未运行的

# top命令

docker top myContainer # 查看container容器中,运行的进程信息

# attach命令

docker attach myContainer #连接到正在运行的myContainer容器

# port命令

docker port myContainer  #列出myContainer容器的端口映射情况

# rootfs命令(文件系统)

  • 一个操作系统所包含的文件、配置和目录,并不包括操作系统内核

# commit命令

docker commit -a "automannn" -m "说明文字" <containerId> automannn:v1 # 将指定容器保存为新的镜像,并添加提交人信息和说明人信息

# cp命令

docker cp <containerId>:/app /app/ #将容器目录拷贝到主机

docker cp /app/ <containerId>:/app #将主机目录拷贝到容器

# 服务端镜像管理命令

# login/logout命令

docker login -u 用户名 -p 密码 [SERVER]  #登录到docker仓库,如果未指定仓库地址,则默认未官方仓库 Docker Hub

docker logout #登出仓库,未配置,则默认为官方仓库

# pull命令

docker pull java #从官方仓库中,下载java最新镜像

# push命令

docker push automannn:v1 #上传本地镜像到仓库,需要先登录

# 推送到harbor仓库

# 如果是build 镜像,则可以直接指定,如
docker build . -t 192.168.10.7:20080/library/natm-natter:v1
docker push 192.168.10.7:20080/library/natm-natter:v1

# 如果是本地的已有镜像,则需先打tag
docker tag natm-natter:v1 192.168.10.7:20080/library/natm-natter:v1
docker push 192.168.10.7:20080/library/natm-natter:v1

# search命令

docker search java # 从镜像仓库中查找所有镜像名称包含java的镜像

# 本地镜像管理命令

# images命令

docker images #列出本地所有的镜像

# rmi命令

docker rmi -f automannn:v1 #强制移除automannn:v1本地镜像

# save命令

docker save -o automann_images.tar automann:v1 #将镜像生成tar文档

# load命令

docker load < automann_images.tar #导入tar镜像

# docker概览命令

# info命令

docker info #查看docker系统信息

# version命令

docker version #查看docker版本信息

# docker网络

  • 安装docker时,会自动创建三个网络,分别为: bridge(容器默认连接到此网络)、none、host
  • 该功能由 docker engine实现,它将在宿主机创建一个docker0的虚拟网桥;通过宿主机的创建虚拟网卡(一对,一端放在宿主机,一端放在容器中),并以该网桥为中介,形成一个二级网络.

# 网络模式的选择

docker run 启动Docker容器时,可以用 --net=选项 指定容器的网络模式

docker run aaa --net=host #指定host模式
docker run aaa --net=none #指定none模式
docker run aaa --net=bridge #指定bridge模式,默认选择此选项
docker run aaa --net=container:NAME_or_ID #与指定容器共享

# host模式

  • 与宿主机共用一个network namespace,容器将不会虚拟自己的网卡等信息,而是直接使用宿主机的IP和端口,注意是使用,而非劫持;

# container模式

  • 与其他容器共享一个network namespace,除网络外,文件系统、进程列表等还是隔离的.

# none模式

  • 该docker容器会有自己独立的network namespace,但不会为docker进行任何网络配置。可借助pipwork工具为docker容器指定ip信息等

# bridge桥接模式

  • 默认的网络模式
  • 为每一个容器,自动分配一个独立的network namespace,默认将docker容器连接到虚拟网桥docker0上;

# Docker运行资源配置

通过命令docker container stats 容器id 可查看容器的资源使用情况

# 内存

# 命令

  • docker run -m 或者 --memory设置内存的使用限额
  • docker run --memory-swap设置交换区swap限额 swap区是使用磁盘作为额外的内存(超过最大内存时),但是其速度较为缓慢,只能在合适的场景中使用

# 实例

  • docker run -m 100M --memory-swap 200M表面该容器最大内存为100M,允许使用的交换区最大为200M

# 内存溢出处理

  • 容器内存超出限制后,docker可能会将容器杀死
  • 通过配置 --oom-kill-disable=false可以保证容器不被docker杀死

# 缺省值

  • 默认情况下,其参数为-1,即没有限制

# CPU

  • 默认情况下,所有容器平等地使用CPU资源
  • 可以通过 -c 或者 --cpu-shares设置容器使用CPU的权重,默认值为1024;

# IO

  • 默认情况下,所有容器能够平等地读写磁盘
  • 通过参数--blkio-weight可改变容器IO的优先级,默认值为500.与CPU类似,它也是一个权重参数。

# Dockerfile镜像构建

# 功能特性

  • 构建自定义镜像: 从基础镜像开始,通过命令,逐步添加所需的软件包,配置环境变量,设置工作目录等,形成一个完整的运行环境;
  • 分层文件系统: 采用类似于git的分层文件系统技术, Dockerfile中的每条指令都会产生一个新的镜像层,这些层可以被共享和复用。
  • 缓存机制: 每个构建步骤的结果都会被缓存,后续步骤如果未发生变化,则直接使用缓存结果,可以显著加速镜像的构建过程。
  • 多阶段构建: 允许定义多个构建过程,每个阶段都可以有自己的基础镜像和构建步骤, 在最终的镜像中只保留必要的部分,减少不必要的文件和层,优化镜像大小;
  • 透明性和可维护: 比 docker commit 创建的镜像具有更高的透明度和可维护性; Dockerfile本身就是一份详细的构建文档, 记录了镜像是如何一步步构建出来的。

# 指令集说明

  • FROM: 指定基础镜像。
  • RUN: 用于执行命令行命令。
  • CMD: 指定容器启动时运行的命令,通常用于启动应用程序。
  • EXPOSE: 声明容器内部的服务端口。
  • COPY或ADD: 将主机中的文件或目录复制到镜像中。
  • WORKDIR: 设置容器内的工作目录。
  • ENV: 设置环境变量。
  • VOLUME: 用于创建挂载点或声明卷。
  • ENTRYPOINT: 设置容器启动时的主要命令,不可被覆盖。

# CMD与ENTRYPOINT的区别

CMD与ENTRYPOINT都是Dockerfile中的指令,它们都可以用来设置容器启动时要执行的命令。尽管两者有相似之处,但在功能和使用场景上存在一些关键区别。

CMD指令

CMD的主要用途是为容器提供默认的执行命令及其参数。这意味着当用户没有通过docker run命令指定任何命令时,CMD中定义的命令将会被执行。然而,如果用户在运行容器时提供了命令行参数,那么这些参数会覆盖CMD中定义的内容 。

CMD有三种形式:

  • 提供可执行文件及参数(exec form),这是推荐的形式。
  • 作为ENTRYPOINT的默认参数(仅提供参数)。
  • shell形式,这种形式会通过shell来执行命令(例如/bin/sh -c)。

例如,下面是一个使用CMD的例子:

FROM ubuntu
CMD ["ping", "localhost"]

如果你基于这个Dockerfile构建了一个镜像,并且在不带额外参数的情况下运行它,它将开始ping localhost。但是,如果你在docker run命令后面指定了不同的命令,如docker run <image> hostname,则CMD中定义的ping命令将被覆盖,而hostname将成为实际执行的命令 。

ENTRYPOINT指令

ENTRYPOINT的目的也是为了设置容器启动时要执行的命令,但它有一个重要的特性:一旦设置了ENTRYPOINT,除非使用--entrypoint选项,否则该命令不会被忽略或覆盖。即使用户提供了额外的参数,这些参数也会作为ENTRYPOINT所指定命令的参数传递给它 。

ENTRYPOINT也有两种形式:

  • exec形式,这同样是最推荐的形式。
  • shell形式,类似于CMD的shell形式。

以下是一个ENTRYPOINT的例子:

FROM ubuntu
ENTRYPOINT ["ping"]

在这个例子中,无论你是否提供额外的参数,容器都会尝试运行ping命令。如果你运行容器时不提供参数,比如docker run <image>,它会报错因为缺少了必要的参数(即目标主机)。但如果你运行docker run <image> localhost,它就会开始ping localhost 。

组合使用

一个常见的模式是同时使用CMD和ENTRYPOINT。在这种情况下,CMD通常用于提供ENTRYPOINT命令的默认参数。这样做的好处是,ENTRYPOINT可以保持不变,而CMD提供的参数可以根据需要轻松地被替换。例如:

FROM ubuntu
ENTRYPOINT ["ping"]
CMD ["localhost"]

当你运行容器时,如果不提供额外参数,默认会ping localhost。如果你想ping其他地址,只需在docker run命令后加上那个地址即可 。

总结来说,CMD更适合作为容器启动时的默认行为,允许用户在运行时覆盖;而ENTRYPOINT更适合定义容器的核心功能,不允许轻易被覆盖,但可以通过CMD或其他方式为其提供参数。

# 个人理解

  • Dockerfile可以大大降低镜像迁移成本;对于最终的环境而言,可以去除大量无效的依赖文件;
  • 有利有弊,其环境的兼容性不如直接commit的情况,毕竟镜像体积在这里;

# build时配置代理

ARG HTTP_PROXY
ARG HTTPS_PROXY
ENV HTTP_PROXY=${HTTP_PROXY}
ENV HTTPS_PROXY=${HTTPS_PROXY}
# 可选:设置 NO_PROXY
ARG NO_PROXY
ENV NO_PROXY=${NO_PROXY}
docker build \
  --build-arg HTTP_PROXY="http://proxy.example.com:8080" \
  --build-arg HTTPS_PROXY="http://proxy.example.com:8080" \
  --build-arg NO_PROXY="localhost,127.0.0.1" \
  -t myimage .
  • 也可直接写死参数,如:
ARG HTTP_PROXY
ARG HTTPS_PROXY
ENV HTTP_PROXY=192.168.10.7:7890
ENV HTTPS_PROXY=192.168.10.7:7890