Docker入门
Docker从应用视角取代虚拟机,并可简化开发环境部署,好好学习学习。

Docker 入门

一、基本情况

Docker让开发者轻松打包应用程序的代码、配置和依赖关系到一个可移植的容器中。
Docker容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云等。这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。
容器可以帮助保证应用程序快速、可靠、一致地部署,其间不受部署环境的影响。
容器是完全使用沙箱机制,相互之间不会有任何接口,就像集装箱之间不会相互影响。

Docker基于Linux底层, 是目前最流行的Linux容器解决方案。

Docker容器和计算机内核交互几乎没有性能损耗。性能优于传统虚拟机通过Hypervisor层与内核层的虚拟化。
但要注意,Docker的租户的root和宿主机root等同,一旦容器内的用户拥有root权限,它就直接具备了宿主机的root权限,进而可进行无限制的操作。相较下,传统虚拟机的租户root权限和宿主机的root虚拟机权限是分离的。

二、Docker技术的三大核心概念

(一)镜像 (Image)

镜像可看作是一个特殊的统一文件系统,存放静态的东西:包括提供容器运行时所需的程序、库、资源、配置等文件,还包含了一些为运行时准备的配置参数(如匿名卷、环境变量、用户等)。
镜像不包含任何动态数据,其内容在构建之后也不会被改变。

Docker Image 可看成是只读模板,通过它可以创建 Docker Container。

镜像有多种生成方法:

  • 从无到有开始创建镜像
  • 下载并使用别人创建好的现成的镜像
  • 在现有镜像上创建新的镜像

镜像(Image)就是很多很多只读层(read-only layer)叠加在一起,形成的统一视角。
AUFS (Advanced Union File System,升级版统一文件系统) 技术是Docker把一个image分成很多只读层layer,这些层合并在一起才成为了一个完整的image。举例说,ubuntu22.04跟ubuntu21.04的image可能只有一点点差别,前三层layer都一样,差别体现在第四层layer上。如果本地已有21.04的image,再pull获22.06时,只需把第四层pull下来。从用户的角度看,只存在一个文件系统,以统一视角隐藏了多层的存在。

补充概念:仓库(Repository):a repository is a set of images.

(二)容器 (Container)

Docker Container 是 Docker Image 的运行实例;是真正运行项目程序、消耗系统资源、提供服务的地方。
Docker Container 是可运行的,提供了Linux系统“硬件”环境。

容器 = 镜像 + 读写层。

容器(container) 的定义和镜像(image) 几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。
当启动一个image做container运行时,docker会在image的只读层上加一层薄薄的可写层。 在container里面做的所有操作都反映在可写层。使用commit命令可以把当前的可写层合并到image的只读层里面,下次再用这个image启动container时就已包括了新的改变。

(三) 注册服务器(Registry)

Docker registry 是存储 docker image 的地方。

Registry 分为公有和私有两种:

  • public (公有):开放。Docker Hub 就是Docker官方的public registry
  • private (私有):自用。除了通过Registry供应商外,也可本地搭建私有Docker Registry。Docker官方提供了Docker Registry的镜像,可以直接使用,做为私有Registry服务。

当用户创建了自己的image之后就可使用 push 命令将它上传到公有或者私有registry,这样下次在另外一台机器上使用这个镜像时候,只需要从registry上pull下来就可以了。

Docker Client <=(pull/push)=> Docker Daemon <=(get/put)=> Doker Registry

  • 运行docker push、docker pull、docker search时,实际上是 docker daemon 与 docker registry 间通信。

三、Docker的基本架构

Docker使用的是 C/S 结构,即客户端/服务器体系结构。
Docker客户端与Docker服务器进行交互时,Docker服务端负责构建、运行和分发Docker镜像。
Docker客户端和服务端可以运行在一台机器上,也可以通过RESTful、stock或网络接口与远程Docker服务端进行通信。

Docker的核心组件包括5个:

1. Docker Client

即Docker客户端。就是Docker提供给用户的命令行界面(CLI)工具。

2. Docker Daemon

即Docker服务器。以Linux后台服务的方式运行,是Docker最核心的后台进程,我们也把它称为守护进程。该进程会在后台启动一个API Server。它负责响应来自Docker Client的请求,完成容器管理操作。

一个Host主机通过一个Deamon管理运行多个image和多个container。

Docker Daemon 运行在 Docker host 上,负责创建、运行、监控容器;构建、存储镜像。具体包括:

  • 向 Docker Registry 获取镜像
  • 通过 graphdriver 执行容器镜像的本地化操作
  • 通过 networkdriver 执行容器网络环境的配置
  • 通过 execdriver 执行容器内部运行的执行工作

Docker Daemon的架构包括3方面:Docker Server、Engine、Job。
Docker Server 接受 Docker Client 的请求,并在 Engine 中处理请求,根据请求类型,创建出多个不同的特定 Job 并运行。

默认配置下,Docker daemon只能响应来自本地Host的客户端请求。如果要允许远程客户端请求,需要在配置文件中打开TCP监听。

Docker Daemon 和 Docker Client 的启动都是通过可执行文件docker来完成的。运行代码通过不同的命令行flag参数,区分两者。

3. Docker Image

4. Docker Registry

5. Docker Container

此外:Dockerfile 是自动构造配置 Image 的文件。形式类似Linux的sh文件,Dockerfile中的命令非常类似于Linux下的shell命令。
Dockerfile解决如下问题:

  • 加载image时不知道这个image里面安装了哪些文件,修改了哪些数据;
  • commit次数多了,使得image变得越来越臃肿;一个image动辄几个G,大文件跑起来不优雅。

四、Docker安装

(一)前提(一般都能满足)

Docker对于Linux内核支持功能、即内核的配置选项有一定的要求(比如必须开启 Cgroup 和 Namespace 相关选项,以及其他的网络和存储驱动等), Docker 源码中提供了一个检测脚本,来检测和指导内核的配置。官方脚本:链接

(二)安装

1. Windows系统的安装

  • 电脑BIOS中开启虚拟化(新电脑几乎都已开启)
  • 控制面板–程序–windows功能,安装“Hyper-V”全部子件
  • 安装wsl2:管理员运行PowerShell,$ wsl --install -d Ubuntu;开启Windows其他产品更新;$ wsl --update
  • 下载安装package:WSL2 Linux kernel update package for x64 machines
  • 安装Docker Desktop
  • 启动,并使用命令行运行 $ docker version$ docker info 检查运行情况。
  • 修改源,否则国内慢。

2. 其他系统的安装

  • (详见官方Documentation)

五、Dockerfile文件的编写

Dockerfile 是自动构建 image 的配置文件, 用户可以使用 Dockerfile 快速创建自定义的image。

# 开头的是注释行。
\ 断行连接。不要在一个word内断行。

1. 开头

(1) FROM Image_Name:Tag 指定制作的image是基于哪个现有image(基础image、父image),并pull下来。可以指定多个FROM
(2) MAINTAINER abcdefg 显示维护者信息。

2. image操作指令

(1) WORKDIR 配合 RUNCMDENTRYPOINT等命令设置image内的当前工作路径。如果是相对路径,则相对前一个WORKDIR。默认路径为 /
(2) COPY <src> <dest> 把宿主机上的文件拷贝到image中。<dest> 是image中的位置。
(3) ADD <url> <dest> copy的高级版,可以指定一个url,由docker自动去下载这个url的文件, 然后拷贝到image中。
(4) EVN 定义一个string变量,例如 EVN aaa=\usr\yyy。使用时用 $aaa${aaa}
(5) RUN <command> 构建image时image中要执行的命令。例如,如果希望image构建好时安装好git,可以在Dockerfile里面写RUN apt-get -y install git。每个RUN命令相当于在原有的image基础上添加了一个改动层,原有image不会有变化;不要太多RUN,改动层多,image臃肿。

3. container启动指令

(1) EXPOSE [<port>...] 指定对外开放的端口。例如开放5000端口EXPOSE 5000;开放两个EXPOSE [5000, 5001]

(2) USER <user>[:<group>] user必须已经建立好的;如不提供group,默认root。

(3) ENTRYPOINT ["executable", "param1", "param2"] 设置容器表现得像一个可执行程序一样。注意:一个Dockerfile中只能有一个ENTRYPOINT,如有多个,则最后一个生效。例如要将container变成可执行的python程序,可以ENTRYPOINT ["python"]

(4.1) CMD ["executable","param1","param2"] 指定启动一个container之后默认执行的命令。
(4.2) CMD ["param1","param2"] 必须指定ENTRYPOINT,然后此CMD命令传递参数。
注意:一个Dockerfile中只能有一个CMD,如有多个,则最后一个生效。当运行Docker命令行带参数时,CMD命令会被Docker命令行的传入参数覆盖。

docker的container是为了某个进程而存在的,当进程结束,整个container也就退出了。例如,CMD service nginx start,container执行之后会马上结束。

当执行 $ docker run 从image启动一个container时,默认/bin/sh -c进入了bash界面。默认启动的bash正好是一直在前台运行的命令,只有使用exit命令退出bash的时候才结束进程。
感觉像是虚拟机,但本质上和虚拟机完全不同,虚拟机需要 poweroff 关机。

4. 实例

FROM ubuntu:22.04
ADD http://mirrors.163.com/.help/sources.list.trusty /etc/apt/sources.list
COPY install.sh /usr/local/src/install.sh
COPY supervisord.conf /usr/local/src/supervisord.conf

RUN apt-get  update && \
    apt-get -y install build-essential && \
    apt-get -y install supervisor && \
    cp /usr/local/src/supervisord.conf /etc/supervisor/supervisord.conf && \
    apt-get -y install openssh-server && \
    apt-get -y install git && \
    apt-get -y install vim && \
    apt-get -y install lrzsz && \
    apt-get -y install libxml2-dev && \
    apt-get -y install  pkg-config libssl-dev libsslcommon2-dev && \
    apt-get -y install libbz2-dev && \
    apt-get -y install libcurl4-gnutls-dev && \
    apt-get -y install libjpeg8-dev && \
    apt-get -y install libpng-dev && \
    apt-get -y install libfreetype6-dev && \
    apt-get -y install libmcrypt-dev && \
    apt-get -y install libxslt-dev && \
    apt-get -y install libgmp-dev && \
    apt-get -y install libreadline-dev && \
    ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h && \
    bash /usr/local/src/install.sh && \
    adduser --gecos '' --disabled-password chenjiayao && \ 
    echo -e '1111\n1111' | passwd chenjiayao && \
    echo -e '11\n11' | passwd root

CMD supervisord -n

六、Docker常用命令

(一)基础

1. Id和Name

每个image和container都有一个唯一的id来标识,这个唯一的id一般很长,但输入时,只要输入若干位能唯一标识即可。还可以给一个image起name,这样也可通过name来操作一个image。Name一般包括用户名,即“user/image_name”。

2. tag

每个image除了名称之外还可以有多个tag,标识同一个image或repository的不同版本。通过<image名或repository名>:<标签>的格式来指定具体是哪个版本,不填默认为 latest

(二)命令体系

$ docker -h 去查看命令的详细的帮助文档。

1. Registry 相关的操作

$ docker search
$ docker push Image_Name
$ docker pull Image_Name

2. Image 相关的操作

(1)从 Dockerfile 建立 image :
$ docker build <Dockerfile_Path|Url> 通过指定路径的Dockerfile创建Image。

  • -t name:tag tag the image name

(2)内部:
$ docker images 列出本地所有的images。
$ docker inspect
$ docker tag
$ docker rmi Image_Id/Image_Name 删除一个image。可能失败,原因包括:

  • container正在运行;
  • container虽然退出,但当前container还保存着运行环境等数据;
  • 删除一个image时有Untagged。这个不是没有删除成功,而是因为有其他image共享这个层,所以并没有真正删除掉这个layer层的数据。

(3)备份和恢复:
$ docker save
$ docker load
$ docker export
$ docker import

3. Container 相关的操作

(1)从image启动一个container:
$ docker run Image_Name 直接启动本地的一个image。这个命令后面可以加很多子参数来开启其他功能。如果本地不存在这个image,那么docker会去官方的Docker Hub去下载。默认保存到/var/lib/docker目录下。

  • --name abcd Assign a name to the container。
  • --link containername Add link to another container。
  • -d run the container in detached mode (in the background)
  • -p 80:80 port 80 of host :(映射) port 80 of container
  • -p 127.0.0.1:80:8080/tcp bind port 8080 of container to TCP port 80 on 127.0.0.1 of host.
  • -e DB=sqlite Set environment variables DB=sqlite。
  • --env-file filename filename里可以设置一组环境变量,一行一个。
  • -v /aaa/bbb:/foo mounts /aaa/bbb directory of host to the container’s /foo。如果/aaa/bbb不存在,会自动新建。
  • --restart=always 默认no,No restart when container exits。unless-stopped restart when container stopped or Docker stopped/restarted。always try to restart the container indefinitely。

$ docker exec Run a command in a running container

  • -d detached mode (in the background)

$ docker attach Container_Name/Container_Id 进入的指定的运行中的container。

(2)从container制作image(保存container内的修改):
$ docker commit 把一个container制作成一个image,即可写层并入只读image。
注意:并入只读层,将隐藏可写层已修改的具体内容,后续使用这个image后将不知道之前改了什么;commit将持续增大image体积。
推荐使用Dockerfile定制Image。

(3)删除container:
$ docker rm Container_Name/Container_Id 删除一个已经退出的container,即删除薄薄一层可写层。

(4)container有3个状态:running;paused;stopped。

$ docker start 从stopped到running;
$ docker restart 从running到running;
$ docker stop 退出当前的container;
$ docker kill 从running到stopped;
$ docker pause 从running到paused;
$ docker unpause 从paused到running。

  • 备注:以上命令的参数为 Container_Name/Container_Id

$ docker ps 列出所有running的container。加 -a 还会列出3个状态全部。
$ docker inspect

(三)一般流程

Dockerfile ==> build ==> run ==> stop == > rm


最后修改于 2024-02-24