Docker入门及常用操作

Docker是什么?

Docker是一个开源的应用容器引擎,可以轻松地为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在本地编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack集群和其他的基础应用平台。

简单的理解,Docker类似于集装箱,各式各样的货物,经过集装箱的标准化进行托管,而集装箱和集装箱之间没有影响。也就是说,Docker平台就是一个软件集装箱化平台,这就意味着我们自己可以构建应用程序,将其依赖关系一起打包到一个容器中,然后这容器就很容易运送到其他的机器上进行运行,而且非常易于装载、复制、移除,非常适合软件弹性架构。

因此,就像船只、火车或卡车运输集装箱而不论其内部的货物一样,软件容器充当软件部署的标准单元,其中可以包含不同的代码和依赖项。 按照这种方式容器化软件,开发人员和 IT 专业人员只需进行极少修改或不修改,即可将其部署到不同的环境。

总而言之,Docker 是一个开放平台,使开发人员和管理员可以在称为容器的松散隔离的环境中构建镜像、交付和运行分布式应用程序。以便在开发、QA 和生产环境之间进行高效的应用程序生命周期管理。

Docker vs. 虚拟机

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

如上图所示,由于容器所需的资源要少得多(例如,它们不需要一个完整的 OS),所以它们易于部署且可快速启动。这使你能够具有更高的密度,也就是说,这允许你在同一硬件单元上运行更多服务,从而降低了成本。

在同一内核上运行的副作用是,你获得的隔离比虚拟机要少。

镜像的主要目标是使环境(依赖项)在不同的部署中保持不变。 也就是说,可以在计算机上调试它,然后将其部署到保证具有相同环境的另一台计算机上。

借助容器镜像,可打包应用或服务并采用可靠且可重现的方式对其进行部署。可以说Docker不只是一种技术,还是一种原理和过程

在使用Docker之前,我们经常会听到,“这个问题在开发环境是正常的!”。而在使用 Docker 后,你不会听到开发人员说:“为什么它能在我的计算机上使用却不能用在生产中?”。开发人员只需说“它在 Docker 上运行”,因为打包的Docker应用程序可在任何支持的Docker环境上执行,而且它在所有部署目标(例如,开发、QA、暂存和生产)上都按预期运行。

名词解释

镜像(Image):一个特殊的文件系统

操作系统分为内核和用户空间。对于Linux而言,内核启动后,会挂载root文件系统为其提供用户空间支持。而Docker镜像(Image),就相当于是一个root文件系统。

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

镜像不包含任何动态数据,其内容构建不会被改变

Docker设计时,就充分利用Union FS的技术,将其设计为分层存储的架构。 镜像实际是由多层文件系统联合组成

镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。

比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。

在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。

因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉

分层存储的特征还使得镜像的复用、定制变得更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。

容器 (Container):镜像运行时的实体

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等 。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。前面讲过镜像使用的是分层存储,容器也是如此。

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照Docker最佳实践的要求,容器不应该向其存储层内写入任何数据 ,容器存储层要保持无状态化。

所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此, 使用数据卷后,容器可以随意删除、重新run,数据却不会丢失。

容器在整个应用程序生命周期工作流中提供以下优点:隔离性、可移植性、灵活性、可伸缩性和可控性。 最重要的优点是可在开发和运营之间提供隔离

仓库 (Repository):集中存放镜像文件的地方

镜像构建完成后,可以很容易的在当前宿主上运行,但是, 如果需要在其他服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry就是这样的服务。

一个Docker Registry中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。

所以说,镜像仓库是Docker用来集中存放镜像文件的地方,类似于我们之前常用的代码仓库。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。

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

这里补充一下Docker Registry公开服务和私有Docker Registry的概念:

Docker Registry公开服务是开放给用户使用、允许用户管理镜像的Registry服务。

一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。

最常使用的Registry公开服务是官方的Docker Hub,这也是默认的Registry,并拥有大量的高质量的官方镜像,网址为:hub.docker.com/

在国内访问Docker Hub可能会比较慢,国内也有一些云服务商提供类似于Docker Hub的公开服务。

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

开源的Docker Registry镜像只提供了Docker Registry API的服务端实现,足以支持Docker命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。

Docker简单安装

Ubuntu为例。

卸载较老版本

$ sudo apt-get remove docker docker-engine docker.io containerd runc

安装仓库

1. Update the apt package index and install packages to allow apt to use a repository over HTTPS:

$ sudo apt-get update

$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

2. Add Docker’s official GPG key:

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

3. Use the following command to set up the stable repository. 

$ sudo apt-key fingerprint 0EBFCD88

pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]

安装容器引擎

1. Update the apt package index, and install the latest version of Docker Engine and containerd, or go to the next step to install a specific version:

$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

2. To install a specific version of Docker Engine, list the available versions in the repo, then select and install:

a. List the versions available in your repo:

$ apt-cache madison docker-ce

  docker-ce | 5:18.09.1~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu  xenial/stable amd64 Packages
  docker-ce | 5:18.09.0~3-0~ubuntu-xenial | https://download.docker.com/linux/ubuntu  xenial/stable amd64 Packages
  docker-ce | 18.06.1~ce~3-0~ubuntu       | https://download.docker.com/linux/ubuntu  xenial/stable amd64 Packages
  docker-ce | 18.06.0~ce~3-0~ubuntu       | https://download.docker.com/linux/ubuntu  xenial/stable amd64 Packages
  ...

b. Install a specific version using the version string from the second column, for example, 5:18.09.1~3-0~ubuntu-xenial .

$ sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io

3. Verify that Docker Engine is installed correctly by running the hello-world image.

$ sudo docker run hello-world

使用脚本安装

除了上面的通过仓库安装,你还可以方便地使用官方脚本进行安装(需要root权限):

$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh

<output truncated>

注意:普通用户需要加入docker组或具备root权限才可使用Docker相关操作命令:

sudo usermod -aG docker your-username

查看版本

$ docker version

正常显示信息,即为安装成功。

卸载Docker Engine

1. Uninstall the Docker Engine, CLI, and Containerd packages:

$ sudo apt-get purge docker-ce docker-ce-cli containerd.io

2. Images, containers, volumes, or customized configuration files on your host are not automatically removed. To delete all images, containers, and volumes:

$ sudo rm -rf /var/lib/docker

Docker的基本操作

docker pull:拉取镜像

在配置完 docker 后,接着就是拉取所需要的镜像了,拉取命令为 docker pull ,通常用法非常简单,就是直接后面再跟随镜像名称即可。基本格式为:

docker pull [镜像名][: 标签]

标签是用来标记仓库里镜像创建者和版本号的,默认访问的仓库为 Docker Hub,版本为 latest,也就是自动获取最新版本。

Docker Hub 官网为:,官网可以直接搜索需要的镜像,查看版本号信息等。

要注意的的是官网仓库的镜像主要分为官方和第三方两种,如下图红框里那种,有官方镜像标识的,那么拉取最新版时可以直接输入镜像名称。

比如想拉取一个最新的Ubuntu镜像,那么直接运行:

docker pull ubuntu

而有的镜像不属于官方认证,属于用户上传的,比如一个用户名为testuser的用户,上传了一个名叫testimage的镜像,那么想要拉取这个镜像的话,则需要斜杠隔开用户名和镜像名,运行:

docker pull testuser/testimage

再比如有的镜像既不是官方发布,版本还特别多,想要拉取特定版本的,比如之前文章提到过的更新狂魔HomeAssistant,那就运行:

docker pull homeassistant/home-assistant:0.93.1

上面这句命令代表的意思为拉取用户名为homeassistant的用户所创建的名为 home-assistant的镜像,并且指定版本号为0.93.1,实际上还是非常好理解的。

另外,很多镜像并不是只有一个标签,继续拿Ubuntu为例,访问 Hub 的 Ubuntu 项目页面查看详情。

说明里可以看到20.04,focal-20201106,focal,latest这四个标签实际都指代的同一镜像,都是最新版的意思,实际拉取下来的镜像也是一样的。

docker的拉取还有其他多种方式,除了标签名以外,还可以使用sha256值这类,但一般入门初期用的很少,不做赘述。

docker image

这个命令可以查看本地已下载镜像,如下图会发现有两个一模一样的镜像,标签分别为 18.04 和 latest,镜像 ID 一样。实际上这两个相同 ID,不同标签的镜像,本质就是同一个,只是有不同的名称标签。

普通镜像的删除命令格式为:

docker rmi < 镜像 id>

在本地只有单个镜像文件的前提下(也就是只有唯一 ID),可以使用这个命令直接删除镜像文件本身。

如果遇到了同一个镜像(ID相同)不同tag的情况,那么就需要使用如下命令来删除指定tag的镜像:

docker rmi 镜像名: 标签名

docker tag

tag也就是标签的意思,这个系列的命令用于给镜像重命名创建一个新的。

镜像默认标签一般是latest或者版本号,有时候不利于区分,可以改成自定义的。

对于已经下载的镜像,可以利用docker tag命令,改名并创建一个新副本,命令格式为:

docker tag 现有镜像: 标签 目标镜像名称: 标签

比如我想把之前下载的标签为20.04的Ubuntu镜像,改名创建一个副本,名为test,新标签为v1,那么可以运行以下命令:

docker tag ubuntu:20.04 test:v1

现有镜像名称也可以用镜像 ID 替代,输入 docker tag 镜像ID test:v1 也是一样的效果。

注意:Docker 里是以镜像 ID 来作为判断依据,如果发现几个镜像有着不同名称或标签,然而ID全都一样,那么它们实际就是同一个镜像,本地也只保存了一份文件

例如我用 ubuntu:20.04 的镜像,创建了test:v1-v5这5个新镜像,可以看到这总共6个镜像的ID都是一样的,实际上本地也只保存了一份文件。

这时如果对这6个相同ID的ubuntu镜像进行删除操作,在删除其中任意5个的时候,实际都只是删除了标签内容,只有删除最后一个时,才会真的删除本地保存的镜像文件。

容器的基本管理命令

docker run

容器的运行命令为 :docker run [OPTIONS] IMAGE [COMMAND] 

docker run 命令整体比较复杂,对应不同需求,用法非常的多,可以对容器进行很详细的定制化,具体参照 Docker 官方文档说明:http://docs.docker.com/engine/reference/commandline/run/。作为基础入门,下面只列举几个常用的指令,毕竟一般情况下个人测试时很多参数还是极少用到的:

-d                          指定容器运行于前台还是后台 
--name=                     指定容器名字 
-p                          指定容器映射的端口。注意写的时候是物理机端口在前,容器端口在后,
                            比如-p 8888:80,那么意思是物理机的8888端口映射给容器的80端口,
                            反过来说也一样
--restart=                  指定容器停止后的策略,可用于设定容器开机自启
-v                          映射容器的某个目录到物理机指定目录
--rm                        容器运行完毕后自动删除
-i                          开启容器输入功能
-t                          开启一个容器内部的终端,一般此命令与-i 连用 

关于 Docker 前台运行和后台的区别

前台运行的意思是容器里运行的指令会直接显示在物理机终端界面里,安装好容器后测试运行的那个hello-world容器就是个典型的例子;后台运行的意思就显而易见了,个人入门的情况下一般是使用后台运行情况居多。

用一个实际例子来说明,比如拉取一个ubuntu镜像, 并创建一个对应的容器,后台运行,名称为ubuntu20.04,将容器里的/home目录映射到外层物理机的/home/username/test目录,将容器的88端口映射到外层物理机的8888端口,那么就可以运行:

docker run -d -p 8888:88 --name=ubuntu20.04 -v /home/username/test:/home ubuntu:latest

注意:创建容器时如果不指定名称,那么会随机生成一个。如果本地没有对应名称镜像,则会自动拉取对应版本(默认latest最新版),所以要么先拉取对应版本镜像,要么创建容器时注意指定镜像版本。

docker run -dit

Docker下载的官方纯净系统镜像可以说是非常的精简,很多命令都不包含。而Docker的规范是当容器里没有前台服务运行时,则认为当前无任务,会自动关闭容器。所以如果用到这类纯净系统镜像,则应该使用 docker run -dit 命令,运行:

docker run -dit -p 8888:88 --name=ubuntu20.04 -v /home/username/test:/home ubuntu:latest

需要注意的是一般只有纯净的系统镜像这类,创建时需要使用 docker run -dit 命令,对于大部分时候本身就是成品软件包的镜像,都只要使用普通的 docker run -d 命令即可,比如Portainer面板,HomeAssistant套件这种。

docker update:对容器追加参数

要是加入创建容器时忘了加某项参数,或者后期需要加入时,可以使用 docker update 命令来追加参数。

例如创建容器时忘了添加开机自启,以上面创建的那个ubuntu容器为例子,可以看到创建时没有加入开机启动参数,假如后面想加上的话,命令格式为 docker update 命令参数 镜像 ID ,实际如下运行即可:

docker update --restart=always 2261a52b5aa1

再来举个复杂例子,用ubuntu:latest镜像创建一个对应的容器附加以下要求:

后台运行;
开机自启;
名称为ubuntu20.04;
容器里的/home目录映射到外层物理机的/home/username目录;
容器里的/home/test目录映射到外层物理机的/home/username/test目录;
容器的88端口映射到外层物理机的8888端口,80端口映射到外层物理机的 8080端口。

那么就可以运行:

docker run -dit --restart=always -p 8888:88 -p 8080:80 --name=ubuntu20.04 -v /home/username:/home -v /home/username/test:/home/test ubuntu:latest

一次同时映射两个端口,以此类推, -p 映射端口和 -v 映射目录命令都可以多个连用来达到自己所需要求。

进入容器

进入容器的命令有 docker attach 和 docker exec 两种。

 docker attach 的命令格式为:docker attach 容器ID或名称 

另一个进入容器的命令为 docker exec ,此命令不能单独使用,后面需要跟随参数,常用的有 -i 和 -t 等,-i 表示终端输入功能开启, -t 表示分配一个终端窗口。跟随的参数大部分和 docker run 可用的一样,具体可参考官方文档。

如果单独使用 -i ,那就等同于向容器里发送指令,物理机的终端界面里只会反馈回来指令运行结果,类似于一半盲操作,与 -t 连用后分配了终端,才会变成普通的SSH样式。

此命令格式为: docker exec 参数 容器ID或名称 对容器内部的指令 

比如同样是进入名为ubuntu的容器,那么就运行:

docker exec -it ubuntu20.04 bash

退出容器

 docker attach 进入之后操作就和常规Linux系统的SSH连接一样了,退出则直接输入exit或者Ctrl+P+Q即可。

但要注意exit指令退出后,容器也会一起停止运行,除非创建时设定了自动重启参数。 Ctrl+P+Q则不会导致容器一起退出

 docker exec 指令进入的容器,任意方法退出均不会导致容器停止运行

docker commit:容器打包

在对容器进行了修改后,如果需要将容器重新打包成镜像,保存起来或者作为备份,那么可以使用 docker commit 命令进行打包,命令格式为:

docker commit 容器ID或名称 新镜像名称

比如想把名为ubuntu20.04的镜像打包起来,新镜像名称为new-ubuntu,那么可以运行:

docker commit ubuntu20.04 new-ubuntu

打包命令本身也可以跟随多种参数,不过一般只是入门的情况下,也不想着给仓库提交镜像这类,直接打包命令基本能满足大多数情况。

其它常用的容器管理命令

docker ps                              显示所有运行中的容器
docker ps -a                           显示所有容器
docker rename 原容器名或容器ID 新容器名    容器重命名
docker rm 容器ID或名称                   删除容器
docker start 容器ID或名称                启动指定容器 
docker stop 容器ID或名称                 停止指定容器     
docker restart 容器ID或名称              重启指定容器

Docker上传镜像

1. 登录

docker login

2. 上传镜像

docker push <repository-name>[:<tag>]

再次使用该镜像就可以直接 docker pull <repository-name>[:<tag>] 来使用了。

注意:

上传的用户仓库名称必须跟远程仓库一致,可以用 docker tag 来打标签。

docker tag image_id username/repository-name:tag

Docker File

DockerFile是镜像的部署文件,有点像makefile,部署一步到位。

1. 编写Dockerfile文件

FROM mysql:8.0
# 基于镜像 ,拉取镜像,比如mysql:8.0

MAINTAINER Min
# 作者信息

RUN git clone https://github.com/PyMySQL/PyMySQL \
    && cd  ./PyMySQL

# RUN 执行命令:使用git命令下载安装包安装

WORKDIR ./PyMySQL
# 设定初始目录

EXPOSE 80
# 暴露80端口

CMD python3 setup.py install
# 运行install命令,只会执行一条cmd命令

2. build该Dockerfile为一个镜像:

docker build --rm --no-cache=true -t docker-test 
  • -t 设定镜像名字:docker-test
  • --rm 如果已存在docker-test镜像,则删除docker-test镜像
  • --no-cache=true build时,禁止缓存

3. 运行镜像即可:

docker run -i -t -p 8080:80 -d docker-test /bin/bash


(整理自网络)

参考资料:

https://www.cnblogs.com/codelove/p/10030439.html

https://docs.docker.com/engine/install/ubuntu/

https://blog.51cto.com/onebig/2316171

posted @ 2020-12-16 13:16  箐茗  阅读(152)  评论(0编辑  收藏  举报