专注前端开发,每年100集免费视频。
首页/视频教程/ 跟胖哥一起学Docker -第一章:初始Docker和基础操作/
跟胖哥一起学Docker -第一章:初始Docker和基础操作
2021-07-21 视频教程 1209031

如果你在一个IT公司,并且是一个技术人员,就一定要学Docker。注意我这里用到了技术人员,也就是说无论是前后端开发还是运维测试,Docker都是必学的技术。

Docker-logo

因为截至到2020年,容器技术(Container)技术在国内一线互联网公司的生产环境中使用比例已经占到了50%。现在是2021年,这个比例一定会有所上升。也就是说容器技术得到了快速的普及。

01.[导语] 为什么要学习Docker技术

现阶段去大厂面试,几乎任何技术岗位,都希望你有容器技术的使用经验。就跟你去面试程序员,必须要面试算法和数据结构一样了。

这也是我为什么要出一套免费Docker视频教程的原因,教大家现实工作中使用的技术,面向工资学习。

一. 自我介绍和教程简介

我相信看文章的大多数都是我的老朋友了,但按惯例,新课开始还是要来个自我介绍。

自我介绍

本套视频完全免费,每周会更新3-5集左右,总更新时间会超过2个月。

所以我们一起学习Docker技术,建议扫码加一下我的微信公众号。这样每次更新你都可以收到提醒信息,保证不落课。我也会在公众号文章的下方回答小伙伴的问题和互动。

本视频讲解的是Docker20.x的版本,也就是说Docker的最新版本。本套课程会专注于容器技术本身,从基础开始到原理的深入都会讲到。

视频正确的观看方法,就是你先看视频,不用作任何的笔记,所有的课程内容,我都会在公众号和博客里进行更新。

需要的前置知识

  • 需要会一门编程语言,可以是Python、JavaScript、Java、C++..........
  • 熟悉基本的Linux命令,因为课程还是面向工作的,所以会以Linux系统为主,进行学习。

二. 简述软件基础架构的发展史

为了先来看一段简单的基础架构历史。

  • 90年代是传统服务器,在一些公司都会买小型机、塔式服务器、刀片式服务器,一个服务器上跑一个服务(一种应用),缺点是大量服务器资源被浪费;
  • 2000年开始流行虚拟化技术,代表是VMware和VirtualBox软件,在一个服务器上可以模拟出多台虚拟服务器,缺点是占有服务器资源较多,需要虚拟内存和CPU,占有服务器大量资源;
  • 2005年-2015年云技术Cloud开始流行,这个时候产生了很多大型云服务商,国际的有亚马逊、国内的阿里云,都是这个时期成长起来的公司。云技术也为容器技术提供了良好的生长土壤。
  • 2015年以后Container(容器)时代,现在无论是国际还是国内大厂,无一例外的都在使用容器技术。那最为出名的就是Docker。

通过这段历史,你可以了解到软件基础架构的变革。所以现在无论时开发人员、还是运维测试人员,都需要会使用容器技术,就像我们会使用基本的操作系统一样重要。

三. Container(容器技术)的概念

我们通过百度查询,可以得到对容器技术的概念。

Linux Container容器技术的诞生(2008年)就解决了IT世界里“集装箱运输”的问题。Linux Container(简称LXC),它是一种内核轻量级的操作系统层虚拟化技术。Linux Container主要由Namespace和Cgroup两大机制保证实现。

这段鬼话非常难理解,我用我的话解释一下,其实容器就想一个打包工具,打包的不仅是你的程序,也包括运行环境。就好比你把你的开发主机和开发程序完全复制了一份,别人拿到后就不需要搭建环境,也不需要根据环境进行调试,直接就可以运行了。

这节算是一个导学内容,简单总结一下:无论你是开发、测试或是运维,都需要学习Docker技术。因为截至2020年Docker在生产环境的使用已经超过50%,并且还在迅速发展。我们还介绍了一下软件基础 架构的发展史。并对Container的概念作了一个基本的介绍。

下节课我们将安装Docker软件,真正开启Docker 的大门。

02.[安装] 在Windos11系统下安装Docker

上节课基本都是理论,作为程序员,我不喜欢理论,能动手尽量不吵吵,这是基本原则。这节我们就在Windows11下安装Docker系统(Docker Desktop for windows)。当然Windows10下的安装方法基本类似,这里选用最新的操作系统Win11。

一.在安装Docker之前的配置

在Windows系统上安装Dcoker之前需要作几项必要的配置,否则就会安装失败。

1.开启BIOS中的虚拟化-BIOS virtualization

这一步每个主版的型号不同,所以开启方法也不太一样。你要根据你的主板型号去网上搜索开启方法。

开启主板虚拟化BIOS virtualization

我这里给出几种主板的开启方式图片,这些图片是不同主板的BIOS和开启BIOS virtualization方法,可以帮助你快速开启。但具体如何开启你的BIOS虚拟化选项,最好的办法还是百度或者Google去根据主板的型号,进行开启。

我的主板是UEFI BIOS 的,重启电脑后狂按Del键,进入BIOS后。按F7进入高级模式,打开advanced高级选项中 cpu congiguration处理器配置中 intel vitualization technology 虚拟化支持选项,设置为enabled开启,F10保存退出即可解决。

这样就开启了主板的BIOS虚拟化(BIOS virtualization) 。

2.在windows10上开启Hyper-V

Hyper-V是微软的一款虚拟化产品,能够实现桌面虚拟化。所以如果是windows10系统,上面是自带Hyper-V的,你只要开启就好。安装Docker需要开启Windows上的Hyper-V功能。

【此处配图-用PowerShell安装Hyper-V】

PowerShell 安装 Hyper-v

  1. 通过管理员身份打开PowerShell控制台。
  2. 运行以下命令:
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

如果无法找到此命令,请确保你以管理员身份运行PowerShell。

安装完成后,需要重启电脑。

3.设置Hyper-V角色和容器

启用Hyper-V之后,需要设置一下Hyper-V的角色,步骤如下。

【此处配图-设置Hyper-V角色】

Win10下的步骤

1.右键单击windows按钮并选择”应用和功能“。

2.选择相关设置下右侧的”程序和功能“。

3.选择”打开或关闭Windows功能“。

4.选择”Hyper-V“和“容器”,然后单机”确定“。

win10开启Hyper-v

Win11下的步骤:

  1. 点击开始按钮,在搜索框里搜索控制面板
  2. 打开控制面板,又上角的查看方式,改为“小图标”
  3. 选择左侧的“程序和功能”选项
  4. 选择“启用或关闭Windows功能”
  5. 找到“容器”和“Hyper-V”选项,把钩打上。

win11开启容器

上面 三个事情做好后,就可以正式开启安装Docker软件了。

二.安装Docker到Windows上

直接去Docker官网进行下载。

Dokcer的官网是- https://docker.com

进入官网后,选择Products(产品),然后选择Docker Desktop,进入下载页面,点击进行下载。这个软件大概有520M左右,所以可能要下载一会(根据网速不同,)。

Docker官网下载桌面版本

下载完成后,双击进行安装。这里直接默认选项安装就好。安装完成后重启电脑。

Docker安装完成-重启电脑

三.测试安装是否成功

重启之后,Dokcer会随系统启动。可以通过命令行输入 docker version 命令来判断是否已经安装成功。如果可以同时出现clientServer 两项,说明已经安装成功了。

类似下面的命令

PS C:\Users\Administrator> docker version
Client:
 Cloud integration: 1.0.17
 Version:           20.10.7
 API version:       1.41
 Go version:        go1.16.4
 Git commit:        f0df350
 Built:             Wed Jun  2 12:00:56 2021
 OS/Arch:           windows/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.7
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       b0f5bc3
  Built:            Wed Jun  2 11:54:58 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.6
  GitCommit:        d71fcd7d8303cbf684402823e425e9dd2e99285d
 runc:
  Version:          1.0.0-rc95
  GitCommit:        b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

总结:这节主要学习了Docker在windows下的安装,简单讲就三步。

  1. 开启BIOS虚拟化设置;
  2. 开启windows的Hyper-V和容器;
  3. 去官网下载Docker桌面版并安装;

好,下节我们再来看看在Linux上如何安装Docker。

03.[安装] Linux下安装Docker

这节我们将在Linux系统下安装Docker,至于如何你能有Linux系统,需要自己想想办法,可以买,可以自己作系统,也可以直接上虚拟机,方法很多。我这里买了一台特价的99元一年的低配置云服务器,用来瞎折腾用的。

操作系统说明

我这里使用Xshell来远程连接主机。我的系统是CentOS7的版本,算是一个比较老的版本。没有用CentOS 8 的主要原因是服务器配置太低,达不到安装CentOS 8的要求。

如果你使用的是Ubuntu系统或者其他版本的LInux系统,不用担心,安装方法几乎是一样的。因为这种安装方法是相对简单快速。

开始安装Docker

安装我们直接使用shell脚本来进行安装,安装脚本的地址如下。

get.docker.com

可以直接使用curl命令下载这个shell脚本

curl -fsSL get.docker.com -o get-docker.sh

这个下载命令并没有成功提示,所以下载完成后,可以使用ls命令查看一下。如果已经存在了,就可以使用sh命令,直接执行这个脚本了。

sh get-docker.sh

回车后就开始安装Docker了。这里需要注意,如果你不是root用户,是需要使用sudo命令或者给用户sudo权限。

安装过程大概要3-4分钟左右,也是主要看网速和服务器性能。

检测是否安装成功

安装完成后,依然通过docker version命令检查是否安装成功。

如果只显示下面的这些信息,也就是只启动了客户端Client

Client: Docker Engine - Community
 Version:           20.10.7
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        f0df350
 Built:             Wed Jun  2 11:58:10 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

这时候要使用systemctl start命令,开启Docker服务端。

sudo systemctl start docker

开启后,再使用sudo docker version来看一下,如果有类似下面的信息,说明已经安装成功了。

Client: Docker Engine - Community
 Version:           20.10.7
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        f0df350
 Built:             Wed Jun  2 11:58:10 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.7
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       b0f5bc3
  Built:            Wed Jun  2 11:56:35 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.8
  GitCommit:        7eba5930496d9bbe375fdf71603e610ad737d2b2
 runc:
  Version:          1.0.0
  GitCommit:        v1.0.0-0-g84113ee
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

总结:在Linux下安装Docker比Windows安装要简单,主要是官方贴心的准备好了对应的shell脚本文件,我们执行就好。但需要注意的是必须要有sudo权限。

本来还应该演示一下Mac系统下的安装,无奈家中贫寒,实在没有Mac电脑。所以如果你是Mac电脑,就自己搜索一下百度,一定也可以安装成功的。

04.[容器] 创建容器相关命令

镜像和容器的区别

在讲如何创建容器前,我们要对Docker中的镜像和容器有个简单的理解。其实这两个东西有类似的地方,也有不同。所以很多时候新手容易把这两个概念弄混淆。这里我用最简单的比喻来讲。

镜像像是一个包含了OS文件系统和应用的对象,类似虚拟机的模板(比如Window10镜像)。如果你是一个开发 者,可以把镜像看成面向对象编程中的只读类(read-only Class)。

容器和镜像几乎一模一样,唯一的区别是镜像是只读的,而容器上面有一个可读写层。所以容器=镜像+读写层。

这里用一张图让你更清楚的了解容器和镜像的区别。

Docker容器和镜像的区别

创建一个新容器

当你明白了什么是镜像和容器后,我们一起试着来创建一个容器。创建容器的命令是。

docker container run < image name >

image代表一个镜像的名称,如果你想使用的镜像名称是nginx,就可以写成下面的样子。

docker container run nginx

如果是使用ubuntu镜像,命令就变成了下面的写法。

docker container run ubuntu

输入完成后,直接回车。如果系统中没有这个镜像,Docker会自动去Docker Hub上拉取对应的镜像到本地,然后执行对应的Shell脚本,脚本会把镜像自动安装到Doker容器里,并最终启动对于的镜像服务。

Docker Hub 是Docker官方的镜像和社区,里边有很多开发者制作好的镜像,我们可以直接使用这些镜像。如果你有能力,也可以制作镜像,并上传到Docker Hub。

注意,这时候容器是在前台运行的。

查看容器的相关命令

创建万容器后,如果查看这个容器的信息和状态那?这时候你可以使用下面的命令。

docker container ls

(ps:注意你这时候需要新打开一个PowerShell窗口,再执行命令)

输入命令后,就会显示出当前已经存在的容器,并且会列出对应的信息。

  • CONTAINER ID : 容器对应的ID,这个是唯一的
  • IMAGE : 使用的镜像名称,显示不同
  • COMMAND : 执行的相关命令
  • CREATED: 创建的时间
  • STATUS: 目前镜像的状态,一般会有两种状态Up和Exited.
  • PORTS: 协议和端口
  • NAMES: 容器的名称,名字是Docker随机生成的

还有一种查看容器的命令,不过这是以前的命令,不建议使用

docker container ps  (不建议使用)

停止容器的相关命令

如果你想停止掉一个正在运行的容器,可以使用下面的命令:

docker container stop <name or ID>

当容器停止后,再使用查看命令进行查看,你会发现没有任何容器。

docker container ls

这时候你要查看你所有容器,包含已经停止的容器,可以加一个-a,参数。

docker container ls -a

删除容器

当我们停止容器之后,容器并没有删除,而只是停止掉了。这时候你可以使用下面的命令删除容器。

docker container rm <name or ID>

相关命令简写方法

  • 容器的创建:docker container run nginx 简写方法 docker run nginx
  • 容器的列出(up): docker container ls 简写方法 docker ps
  • 容器的列出(up和exit):docker container ls -a 简写方法 docker ps -a
  • 容器的停止 : docker container stop 简写方法 docker stop
  • 容器的删除:docker container rm 简写方法 docker rm

容器相关命令

个人建议尽量不要使用简写方法,写全更语义化,减少出错机会。

05.[容器] 多容器操作和强制删除容器的方法

相信通过上节的学习,小伙伴们已经对容器的创建、查看和删除命令有了认识。这节我们讲一下对于多个容器的操作。因为在实际工作中,我们往往管理的都是多个容器,这也是容器的主要特点之一。

创建多个容器

在WIndows环境下我们来作这个,先打开三个PowerShell窗口,然后在每个窗口中输入创建容器的命令,这里以Nginx镜像为例。

docker container run nginx

然后再重新打开一个PowerShell窗口,输入查看命令,查看已经开启的容器。

docker container ls

可以看到现在已经有3个开启的容器了。

PS C:\Users\Administrator> docker container ls
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
91cc350cc044   nginx     "/docker-entrypoint.…"   6 minutes ago   Up 6 minutes   80/tcp    optimistic_kalam
24f7f578deff   nginx     "/docker-entrypoint.…"   6 minutes ago   Up 6 minutes   80/tcp    focused_lovelace
06fbdca5b9fb   nginx     "/docker-entrypoint.…"   7 minutes ago   Up 7 minutes   80/tcp    epic_wright

停止多个容器

现在要把三个容器用一个命令停掉,笨的方法是直接加上ID或名字。

docker container stop  <ID1  ID2  ID3>

但如果你想想,比如这时候有100个容器,我们用这种方法就会非常麻烦。

这时候我们需要学一个新的查看命令,比如只查看现在所有容器的ID,命令如下。

docker container ps -aq

这样就打印出了所有容器的ID,这时候包括没有开启的。

91cc350cc044
24f7f578deff
06fbdca5b9fb
6fcbf0e96849

有了这个命令之后,我们就可以作一个命令组合。

docker container stop $(docker container ps -qa)

命令执行后,会返回给我们容器的编号,说明已经停止了。可以使用下面的命令再次查看。

docker container ls -a 

这时候就可以看到,所有容器不在是up状态了,而是exited状态。

**PS C:\Users\Administrator> docker container ls -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS     NAMES
91cc350cc044   nginx     "/docker-entrypoint.…"   36 minutes ago   Exited (0) 10 seconds ago             optimistic_kalam
24f7f578deff   nginx     "/docker-entrypoint.…"   37 minutes ago   Exited (0) 10 seconds ago             focused_lovelace
06fbdca5b9fb   nginx     "/docker-entrypoint.…"   38 minutes ago   Exited (0) 10 seconds ago             epic_wright
6fcbf0e96849   nginx     "/docker-entrypoint.…"   46 hours ago     Exited (0) 46 hours ago               great_raman**

删除多个容器

会了停止多个容器,那删除多个容器就很简单了。

docker container rm $(docker container ps -aq)

强制删除容器

正在运行的容器,是不可以直接删除的,会报错。我们来做个实验。新建一个容器.

docker container run nginx

然后新开一个PowerShell,直接使用rm命令删除。

docker container rm <ID or Image Name >

这时候会直接报错。报错内容如下。

Error response from daemon: You cannot remove a running container 21d0ec08e126efe73482264a588a3169c9d5b2253e7d53657ab8ddcf0f8302ba. Stop the container before attempting removal or force remove

报错信息大体就是不能删除没有stop的容器。但这时候就是要删除,你可以使用强制删除命令进行删除。

docker container rm <ID or Image Name > -f

输入完成就删除成功了。

这节课就到这里了,我们学习了如何批量停止和删除多个容器的方法。然后又讲了如何强制删除正在运行的容器。

06.[容器] attached 和detached模式

这节学习一下Docker的端口映射和两种运行模式-attached和detached模式。先来看如何把一个容器的端口映射到主机的80端口上。

Docker端口映射

在开启端口映射之前,你首先要之道Docker对应的容器端口是多少。比如Nginx镜像的端口诗80。知道这个端口后,就可以在启动容器的时候,用-p <port:port> 的形式,启用映射了。

用Nginx举例:

docker container run -p 80:80 nginx

等待项目启动后,打开浏览器窗口,在地址栏输入127.0.0.1,就可以打开nginx的默认网址。

Docker端口映射成功

第一个端口是映射到服务器本机的端口;第二个端口是Docker容器使用的端口。 比如你想把Docker的80端口,映射到服务器的90端口。

docker container run -p 90:80 nginx

attached模式

两种模式最简单的对比理解就是:attached模式在前台运行,detached模式在后台运行。

当你打开127.0.0.1网址的时候,PowerShell上打印出了相关的日志(log),平且每访问一次,都会增加一条日志。也就是说Docker容器的日志会实时的展现到窗口并且占用此端口。这种模式叫做attached模式。

Docker端口映射日志

在windows系统下并不是一个完整的attached模式,只是帮我们打印出了Log。现在到Linux服务器上,这时候你按Ctrl+C,就会停止掉Docker服务。而现实中我们工作的环境恰恰是这种Linux环境。

也就是在Linux上你的操作命令,会直接传递个Docker容器。这个缺点就是很容易误操作,比如在公司的生产环境中,你直接一个Ctrl+C,整个服务就崩掉了,你这个月的绩效也就没有了。

所以我们需要一个更好的,更稳定的模式。也就是detached模式。attached模式更适用于容器和程序的调试阶段。

detached模式

detached模式的开启方法,就是加一个参数-d或者--detach

docker run -d -p 80:80 nginx

这次你会看到,和attached模式不同的是,这次输入完命令后,只显示出了容器的编号,并且可以再输入任何命令。就算我们关掉窗口,容器依然运行,也就是他是在系统后台进行运行的。

这种就比较适合在生产环境中运行,停掉和删除容器都需要使用Shell脚本的形式。减少了很多误操作。

detached模式转换attached模式

在运行之后,也有需要调试的时候,Docker提供了两个模式间的转换。比如现在要把detached模式的容器,改为attched模式。

docker  attach <ID or Image Name>

总结一下,本节课共学习了三个知识点,

  1. 如何映射端口,让Docker可以被访问到;
  2. attached模式和detached的使用和优缺点介绍;
  3. 如用把detached模式转换为attached模式

下节课我们学习detached模式下的具体操作。

07.[容器] detached模式下查看logs

这节算是对上节课的一个小补充,所以知识比较少,因为视频不是一次录制,所以就分开了。希望小伙伴们谅解。

detached模式下查看日志

先复习一下上节课的内容,用detached模式开启一个nginx服务,并映射服务器的80端口

docker container run -d -p 80:80 nginx

容器被运行起来了,是detached模式,也就是Docker 的后台运行模式。这时候想要查看后台日志,可以使用下面的命令查看。

docker container logs <ID or Image name>

虽然日志在窗口中出现了,但只打印一次logs,如果想动态一直跟踪日志,可以在命令上加入一个-f

docker container logs -f <ID or Image name>

输入完上面的命令,打开浏览器,在地址栏输入127.0.0.1,也就是访问本地的nginx服务。你会看到日志窗口就会跟踪到最新的日志。

如果想关闭日志跟踪模式,直接用快捷键Ctrl+C就可以结束掉了。

08.[容器] Docker的交互式模式

有时候容器的镜像不是简单的一个服务,而是需要交互的操作系统。例如创建一个Ubuntu系统,然后需要到系统里输入各种Shell命令和系统进行交互。这时候attached模式detached模式就不能满足要求了。需要使用交互模式。

使用Ubuntu镜像并开启交互模式

docker container run -it ubuntu sh

-it代表启用交互模式,sh代表可以使用Shell脚本。当你输入玩这个脚本后,Docker就会进入到交互模式。可以使用ls来得到目录下的文件,也可以使用hostname来查看计算机名称。

这时候你想退出容器和交互模式可以输入exit命令。需要重点说明的是,随着命令退出后,容器也会跟着退出,变成Exited模式。

detached模式下的交互

如果我们想退出交互,但是并不想停止容器。可以先开启detached模式,然后通过命令进入交互模式。我们来操作一下,先删除所有的容器。

docker container rm -f $(docker container ls -aq)

然后再用detached模式创建一个nginx镜像的容器。

docker container run -d -p 80:80 nginx

直接通过下面的命令就可以进入到交互模式下了。(这是我们以后要经常使用的一个命令)

docker exec -it <ID or Image name> sh 

exec是执行的意思,-it交互模式 , sh交互的方式,用shell脚本进行交互

整个命令的意思是:用shell脚本的方式执行交互模式。

进入后可以使用ls来查看容器的文件系统。

这种模式的优点是,再使用exit退出后,服务并不会停止,而只是退出了交互模式。可以自己尝试一下退出,然后使用docker container ls -a来查看一下容器的状态,你会发现依然是 up状态

这个视频主要学习了Docker容器的交互式模式。

  • 一种是创建并直接进入交互模式
  • 另一种是先创建进入detached模式,然后再进入交互模式

两种模式用处不一样,根据自己需要,选择就好。

09.[镜像] 镜像获取和Image Registry

容器(Container)相关的基础知识先暂停一下学习,接下来把精力放在镜像(Image)上。镜像是Docker里最重要的一个知识点,如果你只会创建容器和使用官方的镜像,并不能算是Docker的高手或者是专业选手,只能说会使用Docker。而制作镜像文件,并让广大网友使用,才是每个Docker人的追求。

获取镜像的三个基本途径

  • 从网络社区直接拉取,在Docker里这种社区叫做Registry(登记处)的意思。(pull from registry)
  • 从Dockerfile构建一个镜像,这种像是DIY一个镜像,但是整个构建过程是需要联网,因为需要西在基础镜像,然后根据基础镜像进行构建(build from Dockerfile)。
  • 自有文件的导入,可以从本地导入已经构建好的镜像文件,在没有网络的时候可以用。这个文件是通过 已有的镜像导出来的压缩包,然后就可以进行使用了。

总结:三种方法中最简单的是第一种,一条命令就可以完成。最复杂的是用Dockerfile进行构建,因为要写很多批处理命令Shell,但这正式Docker的魅力所在,也是我们必须要掌握的。

镜像社区的介绍

镜像社区也叫做Image registry(镜像登记处),是拉取和下载镜像的网站,你也可以通过Dockerfile制作镜像,让所有人使用,类似Docker Image专属的简单版GitHub。我经常使用的是两个社区,一个是官方自己的另一个是红帽旗下的Quay.io。

dockerhub

  • dockerhub:网址- https://hub.docker.com/ ,Docker官方社区,在使用Docker时默认的拉取网站。
  • Quay:网址-https://quay.io/ ,这个是Liunx Red Hat (红帽)的旗下一个第三方Docker 社区。

quay.io

这两个网站算是最常用的镜像下载社区了,建议你现在停下视频,去把这两个网站都注册一下。注册很简单,我就不作过多的介绍了。注册好后,可以简单了解一下这两个网站。

需要说的dockerhub对于免费用户是有一些限制的,但是完全不影响学习使用。主要的简直是,现在个人用户或者没注册用户,每天只能拉取100次,最早是6小时100次。

其实就算每天100次,作为学习者也是够用了。但是最为一个使用容器技术的大型机房肯定是不够用的。

10.[镜像] Image镜像的拉取和删除

这节学习一下在Registry上拉取进行到本地、拉取后如何查看镜像列表、相信的镜像信息和删除镜像。

从dockerhub上拉取镜像

当在PowerShell里输入docker image 命令后,会出现对于Image操作的所有命令和提示(算帮助信息吧)。

PS C:\Users\Administrator> docker image

Usage:  docker image COMMAND

Manage images

Commands:
  build       Build an image from a Dockerfile
  history     Show the history of an image
  import      Import the contents from a tarball to create a filesystem image
  inspect     Display detailed information on one or more images
  load        Load an image from a tar archive or STDIN
  ls          List images
  prune       Remove unused images
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rm          Remove one or more images
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
Run 'docker image COMMAND --help' for more information on a command.

这些命令中可以看到pull的使用方法是用于拉取镜像。比如去拉取一个wordpress的镜像来试试。打开hub.docker.com,进入explore后,搜索wordpress. 点击进入主页,右侧会告诉你拉取的方法。

Dockerhub下载镜像

这条命令是docker pull wordpress, 细心的小伙伴一定可以发现,正常应该是docker image pull wordpress,不写image是老版本的写法,你也可以理解为简写,但我依然建议大家把命令写全,也就是带上image

docker image pull wordpress

如果是第一次拉取镜像是需要下载过程的,需要下载很多依赖的基础镜像。具体快慢会和网速有关。这里给出第一次拉取wordpress的日志信息。

PS C:\Users\Administrator> docker image pull wordpress
Using default tag: latest
latest: Pulling from library/wordpress
33847f680f63: Already exists
ba03c99d34ed: Pull complete
5f637ed06e1a: Pull complete
ecfd84713df3: Pull complete
75835d9b84b3: Pull complete
8514983ec064: Pull complete
ec742b42e20a: Pull complete
eec0037df356: Pull complete
12533b9aae46: Pull complete
35321669eeaa: Pull complete
e1b13b2730b4: Pull complete
39fbc18466a3: Pull complete
d1db32813f92: Pull complete
469c3aba411c: Pull complete
5f4ce430d448: Pull complete
282de0644b41: Pull complete
5734bf68e8bd: Pull complete
6c4ac5841412: Pull complete
4e734c3119eb: Pull complete
531c1cccc50d: Pull complete
68155d3faebf: Pull complete
Digest: sha256:b590a25a358650cb91233ef9e058b2785a121f3a9e622d9dfc03a2749004013e
Status: Downloaded newer image for wordpress:latest
docker.io/library/wordpress:latest

上面命令的第二行tag的意思就是版本,latest代表的是最新版。因为这里并没有给版本号,你可以加入版本号进行下载的。到dockerhub上可以找到对应的版本号。比如我们要下载wordpress7.3版本,就可以输入下面的命令。

docker pull wordpress:php7.3-fpm-alpine

从Quay.io上拉取进行

再演示一下如何从Quay.io上拉取镜像,打开Quay的网址https://quay.io。然后搜索node的相关镜像,进入详细页,在右边也是可以看到相关的拉取pull命令的。

quay.io下载镜像

输出的日志结果:

PS C:\Users\Administrator> docker pull quay.io/calico/node
Using default tag: latest
latest: Pulling from calico/node
8127ea9172da: Pull complete
3d02a8db9907: Pull complete
Digest: sha256:0a02d75339eaca89fcca3a8f39b69afba2cff13964c6d3a6a470e508ab4b43e4
Status: Downloaded newer image for quay.io/calico/node:latest
quay.io/calico/node:latest

查看现有镜像

查看镜像列表的方法

docker image ls

通过这条命令就可以查看Docker中有的镜像和相关信息。

查看具体镜像信息

docker image  inspect <IMAGE ID>

这里的inspect- [ɪnˈspekt]检查的意思。执行这条命令后就会显示很多关于这个镜像的详细信息。你现在可能还看不懂这些信息,但是会随着不断深入学习,对这些信息有更深刻的了解。

删除镜像

docker image rm <Image ID>

需要注意的是,当有容器在使用镜像时,是没有办法被删除的。即使容器是停止掉的,依然是没办法删除的。

总结: 这节我们讲解了如何从Registry拉取镜像、查看镜像和删除镜像的方法。命令看起来挺简单,但是里边注意的事情还是挺多的,小伙伴们可以练习一下。

11.[镜像] Docker镜像的导入导出

这节学一下镜像的导入和导出,在工作中经常使用。比如公司来了一个新同事,也会Docker,你正好自己制作了一个公司内部的镜像,就可以把你机器上的镜像导出给他。他拿到镜像之后直接导入,就可以进行开发了,好处是你们的开发环境基本统一了。

还有一种情况,就是生产环境中的服务器是不允许随便上网的,这时候你就需要在一台能上网的电脑上,做好镜像后,直接把镜像导出,供服务器使用。

导出镜像

docker image save

在导出之前,你最好到一个好找的路径下面,比如我这里就选择了D盘,使用mkdir命令创建一个文件夹,进入文件后输入下面的命令。比如现在要导出镜像中的busybox镜像,可以这样写命令。

docker image save busybox:latest -o mybusybox.image

解读上面的命令,save是导出/保存的意思,busybox:latest是镜像名称+版本号, -o代表输出,mybusybox.image是导出后镜像的名字。

命令执行完成后,可以看到在执行命令所在的目录下就会多出一个mybusybox.image的文件,这就是刚才导出的镜像了。

导入镜像

先删除掉本机已有的busybox镜像。

docker image rm busybox

删除后直接导入镜像。

docker image load -i .\mybusybox.image

执行完命令之后,再使用docker image ls命令查看,busybox镜像已经回来了。

这节主要讲解了Docker镜像的导入和导出,这种操作是完全可以离线的。虽然个人使用的并不多,但是在工作中还是经常使用的。

12.[镜像] 初识Dockerfile

已经讲了两种获取Docker镜像的方式,第一种是直接从Registry中拉去,第二种是自己导入导出镜像。今天会学习第三种获得镜像的方法,通过Dockerfile来DIY制作镜像。

通过Dockerfile构建镜像虽然比较麻烦,这是最常使用的一种方式,必须掌握。它的知识点非常多,后期准备专门出一篇文章来讲解这个Dockerfile的使用、语法和注意问题。

什么是Dockerfile

Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。

可以简单总结为下面三点:

  • Dockerfile是用于构建docker镜像的文件
  • Dockerfile里包含了构建镜像所需的”指令“
  • Dockerfile有其特定的语法规则(重要学习)

Demo-执行Python程序

有这样一个需求,制作一个镜像。镜像的操作系统是Ubuntu最新版,然后在系统上运行jspang.py程序。Python程序的内容非常简单,只要打印出Hello JSPang,就可以了。

第一步,安装一个Ubuntu系统。

第二步,下载安装Python环境

apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y python3.9 python3-pip python3.9-dev

第三步,准备jspang.py文件。这个可以在D盘新建一个DockerTest文件夹,然后在文件夹中新建一个jspang.py文件,然后编写下面的文件。

print("Hello JSPang")

第四步,运行jspang.py

$ python3 hello.py
hello docker

这是我们拆解的步骤,有步骤之后,我们看看如何写一个Dockerfile文件(建议把Dockerfile文件和jspang.py文件放在一起个文件夹下)

FROM ubuntu:latest
RUN  apt-get update && \
         DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y python3.9 python3-pip python3.9-dev
ADD jspang.py /
CMD ["python3","jspang.py"]

这算是最简单的一个Dockerfile文件的编写,有了这个文件之后,下节就可以动过Dockerfile来构建一个镜像了。这节你只要对镜像的构建有所了解就可以了。

13.[镜像] 通过Dockerfile构建镜像

上节课算是对Dockerfile的一个初识,这节我们就通过上节课的Dockerfile文件进行 构建。

Dockerfile构建镜像

当有了Dockerfilejspang.py文件以后,通过PowerShell进入到两个文件的文件夹。通过Docker命令就可以完成构建。

docker image build -t <Name:tag> <file path>

例如现在要通过已经写好的Dockerfile,构建一个jspang的镜像,就可以使用下面的命令构建。

docker image build -t jspang .

(注意命令最后是有一个.的),如果你是第一次执行打包,这个过程还是需要2-3分钟的,当出现FINISHED后,说明打包完成了。

打包完成后,可以通过docker image ls命令来查看现在拥有的镜像列表。如果一切正常,你应该可以看到名字为jspang的镜像已经存在了。

可以执行容器,验证一下自己DIY的镜像是否可用。

docker  run jspang

镜像如果正常,应该正确现实出Hello JSPang字样,然后就直接退出容器了。这是跟我们写的Dockerfile有关的。

我尽量把课程分的颗粒度细一点,这样你在工作中遇到问题,通过目录就可以快速定位到知识点,快速学会。

14.[镜像] 把镜像分享到Dockerhub

上节课通过docker image build镜像,已经构建了镜像。这节我们要把镜像push到dockerhub上去,这样就可以让所有人进行使用了。

符合Dockerhub的命名规则

这里我新申请了一个账号,账号名为jspangcom,所以在点开Profile时是没有任何镜像的。

https://newimg.jspang.com/Docker14_1.png

如果你想上传属于自己的镜像,需要遵守社区规则,就是用户ID/镜像名称。可以最简单的方法,就是重新build一个镜像,镜像名称符合社区规则就可以了。

docker image build -t jspangcom/jspang .

这时候就会生成一下新的镜像,但是Image ID 是一摸一样的。

也可以通过docker image tag命令,具体语法如下:

docker image tag <old image name > <new iamge name>

例如把jspang这个镜像,改为jspangcom/jspang镜像,命令可以如下:

docker image tag jspang jspangcom/jspang

推送到Dockerhub上

在推送前,需要先登录Dockerhub账号,登录命令如下:

docker login

执行命令好,会要求输入Username,也就你Dockerhub ID,还需要输入密码。如果输入正确,并出现Login Succeeded就证明登录成功了。

docker image push Name[:TAG]

比如就是把刚才的jspangcom/jspang镜像push到社区,就可以使用下面的命令。

docker image push jspangcom/jspang

输入完命令,就会给我们进行push到Dockerhub上了。这时候你可以到Dockerhub的profile页面,刷新一下,就可以看到刚刚push上去的镜像。

https://newimg.jspang.com/Docker14_2PushImage.png

这样全世界的Docker爱好者都可以使用你自己DIY的镜像了。

15.[Dockerfile] FROM语法和镜像选择

FROM 语法的使用

看上节课视频,咱们一起写的Dockerfile文件.

FROM ubuntu:latest
RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y python3.9 python3-pip python3.9-dev
ADD jspang.py  /
CMD ["python3","/jspang.py"]

第一句就是FROM ubuntu:latest , 它的意思是选择一个基础镜像,我这里选择的是ubuntu系统的最新版。

几乎所有的Dockerfile文件,要做的第一件事就是要选择一个基础镜像。但可能出乎意料,上面的这句FROM ubuntu:latest并不是一个最优写法。

选择基础镜像的三个原则

为什么说FROM ubuntu:latest不是最优写法?先来看有选择镜像的三个基本原则。

  1. 官方镜像优于非官方的镜像;
  2. 固定版本的Tag,而不是每次都使用latest;
  3. 功能满足,选择体积小的镜像;

原则一、官方镜像优于非官方的镜像

我们以Dockerhub 社区为例,现在要找wordpress的镜像。搜索之后,可以看到第一个是官方认证的(Official Image)。三个基本原则的第一个,有官方认证的,直接选择官方认证的。

https://newimg.jspang.com/Docker15-1OfficialImage.png

选择官方镜像至少可以保证没有木马和侵入程序。特别是你如果已经在公司上班,保证容器的安全非常重要。

原则二、固定版本的Tag,而不是每次都使用latest

进入到wordpress镜像详细页面,选择Tags选项卡,会看到很多版本的镜像。有php8.0,也有php7.4的。你需要根据项目需求进行选择,而不是不负责任的每次都选择最新版本。

有些镜像的前后版本是不兼容的,这会给你的工作带来很多麻烦,比如镜像的维护性和稳定性都会存在问题。所以在写Dockfile第一步时,就需要我们做好这些事情。选择固定的版本,而不是每次都使用latest。

https://newimg.jspang.com/Docker15-2dockerfiletag.png

原则三、功能满足的前提下,选择体积小的镜像

这个原则不好把握,需要些经验。前提是满足你需求的情况下,所以这就要对镜像有充分的了解,然后再根据需求选择小的。

还是拿wordpress镜像为例,有些是带alpine环境的,有些是不带的。他们的镜像体积大小相差 一半。

alpine (Alpine Linux)是一款独立的非商业性的通用Linux发行版、关注安全性、简单性和资源效率。它小巧的特点受广大IT人士的喜爱。

在工作中尽量选择自己需要的,如果你不需要alpine环境,你完全可以放弃alpine的环境版本,而是固定的php版本。

https://newimg.jspang.com/Docker15-3alpineTag.png

注意这是基础镜像,在这个基础上,你还会加入很多自己的东西和应用。当你再次build时,镜像体积就会很大,越大的镜像,代表复杂度越高。所以让自己的镜像变的简洁,是我们的责任。

好了,这节课我们学习了FROM语法和选择镜像时的三个基本原则。虽然没有作任何的操作,但是这三个基本原则还是非常重要的。

16.[Dockerfile] RUN执行指令使用技巧

RUN是Dockerfile中一个重要的指令,它可以执行Shell指令,包括下载文件、安装软件、配置环境.....都是可以的。这节课就是学习一下如何使用RUN指令,以及使用RUN指令时的一些小技巧。

在Ubuntu系统下安装ipinfo

纯净的Ubuntu系统是没有ipinfo命令的,在安装完系统后,都会安装ipinfo命令。步骤如下:

$ apt-get update
$ apt-get install wget
$ wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linux_amd64.tar.gz
$ tar zxf ipinfo_2.0.1_linux_amd64.tar.gz
$ mv ipinfo_2.0.1_linux_amd64 /usr/bin/ipinfo
$ rm -rf ipinfo_2.0.1_linux_amd64.tar.gz

上面这段代码需要你会一些Linux 的基本操作,其实就是安装,解压和删除下载文件 的一个过程。

不建议的Dockerfile写法

如果用RUN命令来编写,直接可以写成下面的样子。

FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y wget
RUN wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linux_amd64.tar.gz
RUN tar zxf ipinfo_2.0.1_linux_amd64.tar.gz
RUN mv ipinfo_2.0.1_linux_amd64 /usr/bin/ipinfo
RUN rm -rf ipinfo_2.0.1_linux_amd64.tar.gz

但这样写的问题是,镜像的分层会变的很多,每一个RUN都是一个分层,打出来的镜像包也会变大。

这是一般新手会犯的错误。

把上面的文件写到Dockerfile里,并个文件命名为Dockerfile.bad。执行下面的命令进行打包。

docker image build -f Dockerfile.bad -t ipinfo-bad .

-f为指定打包的名称。 这个过程会很长。打包完成后,可以用查看命令,看一下包的基本信息。

docker image ls

在列表里,看到ininfo-bad镜像的大小134MB。再来看一下具体的分层情况,使用下面的命令查看。

docker image history <Image ID>

查看结果如下:

PS D:\TestDocker> docker image histroy e9c

Usage:  docker image COMMAND

Manage images

Commands:
  build       Build an image from a Dockerfile
  history     Show the history of an image
  import      Import the contents from a tarball to create a filesystem image
  inspect     Display detailed information on one or more images
  load        Load an image from a tar archive or STDIN
  ls          List images
e9c79d165e5c   4 minutes ago   RUN /bin/sh -c rm -rf ipinfo_2.0.1_linux_amd…   0B        buildkit.dockerfile.v0
<missing>      4 minutes ago   RUN /bin/sh -c mv ipinfo_2.0.1_linux_amd64 /…   9.36MB    buildkit.dockerfile.v0
<missing>      4 minutes ago   RUN /bin/sh -c tar zxf ipinfo_2.0.1_linux_am…   9.36MB    buildkit.dockerfile.v0
<missing>      4 minutes ago   RUN /bin/sh -c wget https://github.com/ipinf…   4.85MB    buildkit.dockerfile.v0
<missing>      6 minutes ago   RUN /bin/sh -c apt-get install -y wget # bui…   7.6MB     buildkit.dockerfile.v0
<missing>      6 minutes ago   RUN /bin/sh -c apt-get update # buildkit        29.7MB    buildkit.dockerfile.v0
<missing>      3 weeks ago     /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      3 weeks ago     /bin/sh -c #(nop) ADD file:5c3d9d2597e01d1ce…   72.8MB

正确的Dockerfile写法

把所有执行命令放到一个RUN里,并用&& \进行连接。就可以把很多命令写到一个RUN里边了。

FROM ubuntu:latest
RUN apt-get update && \
    apt-get install -y wget && \
    wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linux_amd64.tar.gz && \
    tar zxf ipinfo_2.0.1_linux_amd64.tar.gz && \
    mv ipinfo_2.0.1_linux_amd64 /usr/bin/ipinfo && \
    rm -rf ipinfo_2.0.1_linux_amd64.tar.gz

这样所有的RUN命令只生成一层image layer。打包出来的镜像也没有那么大了。我们把这个文件写到Dockerfile.good文件里,然后用命令进行打包。

docker image build -f dockerfile.good -t ipinfo-good .

这时候再用docker image histroy <Image ID> 查看分层,就会看到分层少了很多。

PS D:\TestDocker> docker image history e89
IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
e893cd98aa4e   2 minutes ago   RUN /bin/sh -c apt-get update &&     apt-get46.7MB    buildkit.dockerfile.v0
<missing>      3 weeks ago     /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      3 weeks ago     /bin/sh -c #(nop) ADD file:5c3d9d2597e01d1ce…   72.8MB

两个包的体积也会有所变化,good镜像是119MB,bad镜像是134MB

PS D:\TestDocker> docker image ls
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
ipinfo-good           latest    e893cd98aa4e   3 minutes ago    119MB
ipinfo-bad            latest    e9c79d165e5c   14 minutes ago   134MB

总结:文章讲解了Dockerfile语法中RUN的用法和使用技巧。

17.[Dockerfile] Dockerfile中的文件操作

制作镜像的时候,经常需要向镜像里添加文件。在Dockerfile中有两个命令可以向镜像中添加文件COPYADD。这节我们就学习一下这两个命令,并重点了解一下两个命令的不同。

用COPY命令构建镜像

COPYADD命令,在复制普通文件的时候,并没有什么太大的不同,两个命令都可以把本地文件,复制到镜像里。(如果复制的路径不存在,则会自动创建)

现在我们写一个Dockerfile,里边的内容是用基础Node镜像,然后拷贝一个index.js文件进去。

Dockerfile.copy内容如下.

FROM node:alpine3.14
COPY index.js  /app/index.js

引用node3.13版本,然后把index.js文件,拷贝到app目录下面。

index.js文件如下。代码是我们在3000端口上,开启了一个最简单web服务,然后返回了Hello Nodejs两个单词。

  //1. 导入 http 模块
    const http = require('http');
    //2. 创建服务器对象
    const server = http.createServer();
    //3. 开启服务器
    server.listen(3000, () => {
        console.log('Server is running...');
    });
    //4. 监听浏览器请求并进行处理
    server.on('request', (req, res) => {
        // end方法能够将数据返回给浏览器,浏览器会显示该字符串
        res.end('Hello Nodejs');
    });

两个文件准备好以后,用build命令进行构建。

docker image build -f Dockerfile.copy -t hello-copy .

构建完成后,可以使用docerk image ls命令进行查询。生成成功后,可以启用交互模式,再加上映射端口的形式,运行容器。

docker container run -it -p 3000:3000 hello-copy sh

这里映射了3000端口,这样我们就可以用127.0.0.1:3000进行访问了。

用ADD构建镜像

ADD 构建镜像和COPY最直观的一点不同,是ADD命令可以直接解压gzip压缩文件,这当我们有很多文件要上传操作的时候,就会变的简单很多。

Dockerfile.add文件内容

FROM node:alpine3.14
ADD index.tar  /app/

ADD命令进行打包镜像

docker image build -f Dockerfile.add -t hello-gzip .

打包好以后使用交互模式,开启容器。

docker container run -it -p 3000:3000 hello-gzip sh

再进入app路径下面,可以看到下面自动给我们解压了index.tar文件。

切换工作目录 WORKDIR

在写Dockerfile文件时,默认的操作目录,是镜像的根目录。但有时候需要拷贝很多内容到镜像里是二级目录,就可以使用WORKDIR命令。把工作目录切换到二级,WORKDIR命令像我们操作linux下的cd命令。

比如还是刚才的Dockerfile.add文件,我们可以使用WORKDIR命令,改成下面的形式。

FROM node:alpine3.14
WORKDIR /app
ADD index.tar  index.js

这时候进入系统后的工作目录,就是在/app下面了。

总结:这节主要讲了COPYADD命令的区别,也讲了 WORKDIR命令的用法。主要关注他们的用途,根据自己的需求进行使用。

18.[Dockerfile] Dockerfile中的ARG和ENV

ARGENV 是经常容易被混淆的两个Dockerfile语法,它们都可以用来设置一个“变量”。但其实两个语法在细节上有很多不同,所以我们放在一节上,对比来讲。

如果你会一门编程语言,这两个语法和定义变量是一样的。这节课学起来也会容易很多。

ENV定义变量

在16节的时候,我们写了一个Docerkfile.good的文件,文件内容如下。

FROM ubuntu:latest
RUN apt-get update && \
    apt-get install -y wget && \
    wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linux_amd64.tar.gz && \
    tar zxf ipinfo_2.0.1_linux_amd64.tar.gz && \
    mv ipinfo_2.0.1_linux_amd64 /usr/bin/ipinfo && \
    rm -rf ipinfo_2.0.1_linux_amd64.tar.gz

这段文件里有ipinfo的版本是ipinfo-2.0.1,这个版本是有可能改变的。文件里一共出现了5次2.0.1,修改起来已经比较麻烦了,如果出现更多次,几乎变的不可维护。所以这时候就需要定义一个变量,方便日后的维护。

先用ENV的形式来修改变量,把上面的Dockerfile.good文件修改为下面的形式

新建一个Dockerfile.ENV的文件,拷贝Dockerfile.good的代码。

这里有个小坑需要给大家说一下,就是注意在写变量时,值不要有任何的空格,否则在打包时会失败。

FROM ubuntu:latest
ENV VERSION=2.0.1
RUN apt-get update && \
    apt-get install -y wget && \
    wget https://github.com/ipinfo/cli/releases/download/ipinfo-${VERSION}/ipinfo_${VERSION}_linux_amd64.tar.gz && \
    tar zxf ipinfo_${VERSION}_linux_amd64.tar.gz && \
    mv ipinfo_${VERSION}_linux_amd64 /usr/bin/ipinfo && \
    rm -rf ipinfo_${VERSION}_linux_amd64.tar.gz

这样写之后,如果以后版本改变了,我们只要修改一处,就可以完成所有的修改了。

我们现在来构建一下这个ENV的镜像。

docker image build -f Dockerfile.ENV -t ipinfo-env .

打包后,先把打包的镜像放在那里,再来看一下ARG的用法和打包。

ARG定义变量

跟上面的方法一样用ARG定义变量效果是一样。只是把ENV换成了ARG

这个文件是Dockerfile.ARG,内容如下。

FROM ubuntu:latest
ARG VERSION=2.0.1
RUN apt-get update && \
    apt-get install -y wget && \
    wget https://github.com/ipinfo/cli/releases/download/ipinfo-${VERSION}/ipinfo_${VERSION}_linux_amd64.tar.gz && \
    tar zxf ipinfo_${VERSION}_linux_amd64.tar.gz && \
    mv ipinfo_${VERSION}_linux_amd64 /usr/bin/ipinfo && \
    rm -rf ipinfo_${VERSION}_linux_amd64.tar.gz

我们可以通过命令来构建一下ARG的镜像。

docker image build -f Dockerfile.ARG -t ipinfo-arg .

两个打包完成后,用docker image ls 查看一下两个镜像,可以看到两个镜像的大小是一样的。都是119M

那我们再来看看ARGENV有什么不同。

ARG和ENV的不同点

总的来说ARGENV有两点不同,第一点是声明变量的作用域不同,第二点是ARG声明后,可以在构建时修改变量。

1.ARG是构建环境 , ENV可带到镜像中

用交互模式进入到ipconfig-env镜像中,然后输入env可以看到当前镜像的信息。

docker container run -it ipinfo-env

然后输入env,可以看到里边是会有VERSION变量的。

2.ARG可以在构建镜像时改变变量值

在构建时,可以使用—build-arg 参数来更改变量的值,比如现在要把变量VERSION的值进行修改,就可以使用下面的命令。

docker image build -f Dockerfile.ARG -t ipinfo-arg-2.0.0 --build-arg VERSION=2.0.0 .

这时候我们再使用交互模式,开启ipinfo-arg-2.0.0容器。

docker container run -it ipinfo-arg-2.0.0 

然后再通过shell命令,ipinfo verison查看ipinfo的版本,可以看到版本已经变成了2.0.0了。

总结:ARGENV都用于声明变量,但是两者也是有区别的,我个人更喜欢ARG来声明,因为信息更多一点。

19.[Dockerfile] CMD容器启动命令

当设置好基础环境,安装完对应软件,处理完文件后。有时候需要启动某个默认命令。CMD用来设置容器启动时默认会执行的命令。

批量清理容器和镜像

在开始学习之前,我们先来学两个批量处理命令。随着我们学习,容器和镜像也越来越多。这时候需要一些批量操作命令。

批量删除不再使用的容器 , 注意这个是批量删除已经退出的容器(Exited state)。

docker system prune -f

同样可以使用下面的命令,删除没有使用的所有镜像。

docker image prune -a

这个命令输入之后,会提示确认,确认后才会真正删除。当我们把所有的容器和镜像都删除后,再继续向下学习。

CMD命令的三个基本特性:

CMD命令在使用时,有三个基本原则需要我们遵守。

  • 容器启动时默认执行的命令
  • 如果docker container run启动容器时指定了其它命令,则CMD命令会被忽略
  • 如果定义多个CMD,只有最后一个CMD执行

新建一个文件Dockerfile.base文件,拷贝上节课的Dockerfile.ENV文件到新文件中,进行构建镜像。

FROM ubuntu:latest
ENV VERSION=2.0.1
RUN apt-get update && \
    apt-get install -y wget && \
    wget https://github.com/ipinfo/cli/releases/download/ipinfo-${VERSION}/ipinfo_${VERSION}_linux_amd64.tar.gz && \
    tar zxf ipinfo_${VERSION}_linux_amd64.tar.gz && \
    mv ipinfo_${VERSION}_linux_amd64 /usr/bin/ipinfo && \
    rm -rf ipinfo_${VERSION}_linux_amd64.tar.gz

有了文件以后,我们再构建这个镜像。

docker image build -f Dockerfile.base -t ipinfo-base .

构建完成以后,用交互模式启动镜像,

docker container run -it ipinfo-base

启动后,就进入了Shell模式,这是因为ubunt进行里有定义CMD命令。它为我们作了这个事情。

通过查看分层信息,可以看到ubuntu镜像里已经使用了 CMD命令。

PS D:\DockerTest> docker image history ipinfo-base
IMAGE          CREATED        CREATED BY                                      SIZE      COMMENT
11217f4813e6   24 hours ago   RUN /bin/sh -c apt-get update &&     apt-get…   46.7MB    buildkit.dockerfile.v0
<missing>      24 hours ago   ENV VERSION=2.0.1                               0B        buildkit.dockerfile.v0
<missing>      2 weeks ago    /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      2 weeks ago    /bin/sh -c #(nop) ADD file:524e8d93ad65f08a0…   72.8MB

启动容器时指定命令

在用shell命令启动容器的时候,是可以指定相关的CMD命令的。比如我们在创建容器的时候,就启动ipinfo命令。

docker container run -it ipinfo-base ipinfo version

输入完上面的命令,可以看到控制台打印出来了2.0.1,就是ipinfo版本号。

CMD的写法

现在我们向Dockerfile.base文件里,加入一个CMD命令。

FROM ubuntu:latest
ENV VERSION=2.0.1
RUN apt-get update && \
    apt-get install -y wget && \
    wget https://github.com/ipinfo/cli/releases/download/ipinfo-${VERSION}/ipinfo_${VERSION}_linux_amd64.tar.gz && \
    tar zxf ipinfo_${VERSION}_linux_amd64.tar.gz && \
    mv ipinfo_${VERSION}_linux_amd64 /usr/bin/ipinfo && \
    rm -rf ipinfo_${VERSION}_linux_amd64.tar.gz
CMD ["ipinfo","version"]

CMD的写法。

CMD ["ipinfo","version"]

先删除已经有的镜像,然后从新构建镜像。

docker image build -f Dockerfile.base -t ipinfo-base .

然后开启交互模式,启动容器。

docker container run -it ipinfo-base

总结:这节讲了CMD命令使用的三个基本原则,然后简单讲解了CMD命令的编写方法。

20.[Dockerfile] ENTRYPOINT命令的使用

ENTRYPOINT 命令很容易和 CMD命令混淆。ENTRYPOINT也可以设置容器启动时要执行的命令。使用起来的语法很简单,这节主要学习目的是理解ENTYPOINTCMD命令的区别。

ENTRYPOINT和CMD的区别

  • CMD设置的命令,可以在 docker container run 时传入其它命令,覆盖掉 CMD 的命令,但是ENTRYPOINT所设置的命令时一定会被执行的。
  • ENTRYPOINTCMD 可以联合使用, ENTRYPOINT 设置执行的命令,CMD传递参数。

三种镜像Dockerfile说明

编写三个Dockerfile文件,Dockerfile-cmdDockerfile-entrypointDockerfile.

Dockerfile-cmd内容

FROM ubuntu:21.04
CMD ["echo","hello docker"]

Dockerfile-entrypoint内容

FROM ubuntu:21.04
ENTRYPOINT ["echo","hello docker"]

Dockerfile内容

FROM ubuntu:21.04
ENTRYPOINT [ "echo"]
CMD []

对三个Dockerfile文件分别打包,打包成了下面三个镜像包。

demo-cmd          latest    25bb1dee8c29   2 weeks ago   80.3MB
demo-entrypoint   latest    214b876fc74c   2 weeks ago   80.3MB
demo-both         latest    6c64ebc22c19   2 weeks ago   80.3MB

使用的区别和方法

demo-cmd 镜像的使用

我们先来看第一个镜像的使用。

$docker container run --rm -it demo-cmd
hello docker

容器开启后,会直接输出hello docker。这时候如果我们在docker container run里直接加入命令,就会覆盖掉现在显示出的hello docker

$docker container run --rm -it demo-cmd echo "hello world"
hello world

从输出结果可以看出,hello docker这个输出被覆盖掉了,只执行了docker container run中后输入的命令。

demo-entrypoint镜像的使用

启用demo-entrypoint镜像的容器,会直接输出hello docker。说明entrypoint定义的命令也被执行了。

$ docker container run --rm -t demo-entrypoint
hello docker

docker container run 命令后面,加入一个echo "jspang.com",来看一下结果。

$ docker container run --rm -t demo-entrypoint echo "jspang.com"
hello docker echo jspang.com

注意,这里在hello docker后面,打印出了echo jspang.com,而不是jspan.com。说明了它不是执行了两条命令,而是把docker container run后面的命令作为了参数,进行传递了过去。

demo-both镜像的使用

当我们看到了demo-entrypoint镜像的使用后,再回头来看Dockerfile的内容,就能理解他的用途了。

FROM ubuntu:21.04
ENTRYPOINT [ "echo"]
CMD []

意思是用ENTRYPOINT执行echo命令,但最终打印出的结果,CMD来作决定。实现了ENTRYPOINTCMD的配合使用。

现在可以使用docker container run,传递参数,最终输出你想要的结果

$ docker container run --rm -t demo-both "hello jspang"         
hello jspang

总结:这节课主要学习了ENTRYPOINTCMD命令区别,还学习了两个命令的联合使用方法。

21.[数据持久化] VOLUME让数据持久化-1

容器删除掉后,里边的数据也会跟着删除。数据的保存和重复可用这是最基本的要求,也就是常说的数据持久化。在写Dockerfile的时候可以用VOLUME命令,指定数据持久化。这节课就一起学习一下。

不能持久化的案例演示

对比的学习效果最好,所以这里先操作一个不能持久化的案例。当我们了解问题后,再学习持久化就更容易理解和重视。先运行一个官方的Ngix的容器。

docker container run -d nginx

-d是服务运行模式,这个在之前的课程中已经讲过了。

服务运行后,用下面的命令进入交互模式.

docker container exec  -it <Container ID> sh

进入到交互模式后,为了体现数据持久化,安装一下Vim编辑器。安装vim编辑器的命令如下。。

apt-get update
apt-get install vim

安装好Vim后,进入app目录。

vim test.txt

test.txt文件里,写入Hello JSPang.com,然后用:wq,进行保存。但是如果这时候删除了容器,我们写的文件就消失了。

照顾一下没什么经验的小伙伴,简单说一下vim编辑的使用。按i+Enter是进入插入模式,按ESC是退出当前模式,输入:wq是保存并退出。

VOLUME命令实现持久化操作

当知道了容器中的数据不能持久化后,可以在编写Dockerfile时用VOLUME命令设置持久化的目录。

新建一个Dockerfile文件

CentOS下,新建一个test目录,然后在test目录下,新建一个Dockerfile文件,使用vim编辑文件,写入下面的命令。

FROM NGINX
VOLUME ["/app"]

有了Dockerfile文件后,开始构建镜像,

docker image build -t my-image .

构建好镜像,启动镜像容器。

docker container run -d my-image

启动后查看容器ID。

docker container ls

进入交互模式

docker container exec -it <ContainerID> sh

再安装vim.

apt-get update
apt-get install vim

这时候再新建一个app目录,然后编写test.txt文件。

Hello JSPang.com

这时候,再删除镜像,就可以找到我们持久化的数据了。那这些持久化的数据被保存到了那里哪?这就需要我们再学习一下docker volume的相关命令了。

docker volume 相关命令

现在退出容器,来到CentOS当中,可以输入下面的命令,就可以看到docker volume相关的命令了。

# docker volume

Usage:  docker volume COMMAND

Manage volumes

Commands:
  create      Create a volume
  inspect     Display detailed information on one or more volumes
  ls          List volumes
  prune       Remove all unused local volumes
  rm          Remove one or more volumes

Run 'docker volume COMMAND --help' for more information on a command.

可以用docker volume ls 查看所有的持久化空间,最主要的是可以看到存储空间的ID

有了 ID之后,使用下面的命令,可以查看到持久化的具体地址。

# docker volume ls
DRIVER    VOLUME NAME
local     c9fe0c3841af7d052034df6c1bc0b6092c75d9fb9a83d6d7a849ce465981a4d8
# docker volume inspect c9fe0c3841af7d052034df6c1bc0b6092c75d9fb9a83d6d7a849ce465981a4d8
[
    {
        "CreatedAt": "2021-08-16T10:07:52+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/c9fe0c3841af7d052034df6c1bc0b6092c75d9fb9a83d6d7a849ce465981a4d8/_data",
        "Name": "c9fe0c3841af7d052034df6c1bc0b6092c75d9fb9a83d6d7a849ce465981a4d8",
        "Options": null,
        "Scope": "local"
    }
]

其中的Mountpoint就是持久化的地址,复制这个地址,然后用cd命令进入。

cd /var/lib/docker/volumes/c9fe0c3841af7d052034df6c1bc0b6092c75d9fb9a83d6d7a849ce465981a4d8/_data

然后输入ls,就可以看到在进行中我们编辑的test,.txt文件了。这时候再删除容器,这个文件也是存在的。

这节课先到这里,下节课继续学习Volume,把持久化的数据,用到新的容器中。

22.[数据持久化] Volume让数据持久化-2

通过上节课的学习,你已经会把容器(container)中的数据和文件,保存在操作系统上了。现在的需求是,再创建一个容器,新容器如何用我们之前用volume保存下来的的持久化数据?

这节课就学习一下,如何在新容器中使用已经存在的持久化数据。

给volume起名字,实现复用

想要复用持久化数据很简单,就是给volume起个名字。

在启动一个容器的时候,可以使用-v,给容器中的volume起一个名字。比如还使用我们之前自己创建的镜像my-image

docker container run -d -v <Volume name:Dockerfile VOLUME path>   my-image

例如启动容器的时候给volume起个名字叫my-data,然后指定Dockerfile中的VOLUME命令路径。因为一个Dockerfile中可能有多个VOLUME命令,所以这里一定要准确指定路径。(注意是Dockerfile中VOLUME命令下的路径)。

docker container run -d -v my-data:/app my-image

这时候再查看volume,这时候的VOLUME NAME就不是一大串类似ID的东西了,而是我们起的名字。

# docker volume ls
DRIVER    VOLUME NAME
local     my-data

再通过下面的命令,查看一下持久化的详细地址。

# docker volume inspect my-data
[
    {
        "CreatedAt": "2021-08-18T15:12:51+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/my-data/_data",
        "Name": "my-data",
        "Options": null,
        "Scope": "local"
    }
]

进入容器,修改数据

为了证明数据可以复用,现在我们进入容器,然后新建一个test.txt文件,写点内容。

进入容器的交互模式

docker container exec -it <Docker ID> sh

再进入到/app目录下面,然后用echotest.txt文件里写入内容。

echo "Hello mybaby!" > test.txt

删除容器后,重新开启容器

现在强制删除刚才的容器。

docker container rm -f <Container ID>

删除以后看一下volume是否还在,答案是肯定的,一定是在的。

# docker volume ls
DRIVER    VOLUME NAME
local     my-data

现在我们用这个镜像,再启动一个容器。

docker container exec -it <Container ID>  sh

然后再查看test.txt内容,可以看到内容已经回到了容器中,可以继续修改并使用了。

23.[数据持久化] Bind Mount 实现数据持久化

数据持久化除了Data Volume外,还有一种叫做Bind Mount,从中文翻译来讲,就是挂载绑定。简单讲就是把容器中持久化的数据,绑定到本机的一个自定义位置。这节就学习一下这个知识。

我喜欢用Bind Mount 的两个理由

个人很喜欢这种Bind Mount的形式,主要有两个原因。

  1. Data Volume在WIndows环境中很难使用,因为路径是虚拟机的路径,不容易找到。
  2. Bind Mount 设置更简单,可以和开发环境更好的融合。

所以如果你是一个开发者,建议你在开发时,更多的使用Bind Mount实现数据持久化。

Bind Mount命令的使用

使用Bind Mount进行数据持久化的方法,和Data Volume类似,也需要在启动容器的时候用到-v参数,只是参数的编写结构不同。

比如在windos11下进入PowerShell,运行一个Node的容器,然后把/app目录作为,把本机的当前目录作为绑定目录,意思是容器中的app目录和本机的当前目录绑定到了一起。命令如下:

docker container run -it -v ${pwd}:/app node

上面命令具体的意思是,用Bind Mount的形式,开启一个node容器。然后进入交互模式。

其实这时候就实现了Bind Mount的数据持久化。而且你可以在本机新建和操作内容,然后在容器中运行。

本机编写index.js插件

比如在本机的绑定目录新建一个index.js文件,然后每秒钟显示一下时间。

console.log('show Time')
setInterval(()=>{
    console.log(Date())
},1000)

写完这个文件后,到PowerShell里也是可以看到这个文件的。这样就算本机没有Node环境,可以在容器中进行使用。

进入容器的/app 目录,运行node index.js命令,就可以显示时间了。

总结:本节你需要学会Bind Mount的用法,主要是明白和Data Volume的区别,然后根据自己的喜好进行使用。

24.[网络] 容器的端口转发

如果你在外网的Linux服务器上启动了一个Wordpress的容器,然后想通过本机访问,这时候就需要使用端口映射了。如果不进行端口映射,容器相当于一个私域IP,外网是访问不到的,所以要使用端口转发的形式,才可以正常访问。

这节课我们学习的目标就是在腾讯的云主机上安装一下Wordpress容器,然后映射端口,最后在本地机器上可以访问。

Linux主机安装Wordpress

现在我用XShell连接到了腾讯的云服务器(你可以理解为一台真实的云服务器,其实也是用的云容器技术)。在服务器上,我们先安装和启动容器,并映射80端口。

docker container run -d -p 80:80 wordpress

安装的过程也非常简单,大概1分钟就可以启动好。注意这里的-p 80:80 ,这里第一个80,是你要映射的端口好,后边的80,是镜像提供的端口号。

等待完成后,直接在本地浏览器里查看,我的服务器网址是http://110.40.130.171 ,这就就可以访问到Docker容器提供的Wordpress服务了。

如何查看容器提供的端口

上面的操作看似很简单,是因为我们直接知道了一个关键性因素,就是容器提供的端口80。如果不知道容器提供的端口就需要用下面的命令查看容器提供的端口。

# docker container inspect --format '{{.Config.ExposedPorts}}' <ContainerID>
map[80/tcp:[]]

--format 是格式化过滤的意思,后边{{ ...}}里边的是要查看的选项。

如果镜像提供了这样的端口配置就可以查看到了。如果你不知道有什么具体项,可以使用下面的命令查看所有详细信息。

# docker container inspect <Contaienr ID>

这里边有很多信息,如果你有时间,可以详细的一个个看一下。一定会对你的学习有所帮助的。

总结:这节我们主要详解了容器的端口转发的操作方法,顺便讲了讲如何查看容器的详细信息。

25.[docker-compose ]介绍和安装

什么是Docker-compose?

熟悉Linux都知道,我们可以把很多相关的命令写成一个xxx.sh文件,而且这些步骤也是相对固定的。

这样直接运行sh文件,就可以逐一执行很多相关的Docker命令。这种形式可以减少出错和解决复用问题。Docker很贴心的为我们准备了一个专门的工具docker-compose,实现类似sh文件的功能。让我们更加轻松的实现多Docker命令的操作。

你也可以把docker-compose就是把很多Docker命令写入一个专属的文件docker-compose.yml,然后执行这个文件,就可以直接启动我们想要的容器。docker-compose也为我们提供了对应的操作命令。

  • docker-compose up
  • docker-compose stop

也就是说,操作docker-compose 会有两个大的部分需要操作:

  • 第一部分是docker-compose.yam文件
  • 输入命令执行构建容器

docker-compose的安装

对docker-compose了解后,讲一下docker-compose如何安装。

Windows & Mac安装

如果你是Windows或者Mac安装了docker 桌面版本(desktop)以后,就默认安装了docker-compose工具了。可以直接进行使用。

查看安装的版本方法:打开PowerShell后输入下面的命令。

# docker-compose --version
docker-compose version 1.29.2, build 5becea4c

从上面的信息可以看到,我当前的版本是1.29.2。出现这个信息也证明你安装好了。

Linux官方推荐方法安装

Linux系统默认是没有安装docker-compose工具的,可以进入下面的网址。

https://docs.docker.com/desktop/

进入亡之后,选择Product Manuals —>Docker compose—>Liunx后,可以看到三条命令,依次执行就可以安装docker-compose工具了。

第一条命令:

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

如果一次安装不成功,可以多安装几次。一般是网络问题。

第二条命令:

sudo chmod +x /usr/local/bin/docker-compose

第三条命令:

sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

安装好以后,用docker-compose —version 进行检查,如果能出现版本,说明安装成功了。

Linux用pip命令安装

如果你对Python很熟悉,使用pip进行安装是明智的选择。它是python用于安装和维护Python包的。

如果Linux系统上没有pip工具,可以通过下面四个命令进行安装pipdocker-conpose(由于安装时间比较长,我就不演示了,可以自行安装测试)。以下方法适合centos系统。

1.查看是否安装依赖包

sudo yum install epel-release

2.更新文件库(如果不更改yum源此过程消耗时间很长)

sudo yum -y update

3.安装pip

sudo yum -y install python-pip

4.安装docker-compose

sudo pip install -U docker-compose

这个教程就先提供这两种安装方式,你可以自行选择适合自己的安装方式。下节课我们来熟悉一下

compse文件的结构和版本。

26.[docker-compose]文件的结构和版本

yaml文件的基础结构讲解

yaml文件里是对启动镜像相关设置的所有描述,下面就逐一讲解一下。

基本的yaml格式docker-compose.yml

version: "3.8"

services: # 容器
  servicename: # 服务名字,这个名字也是内部 bridge网络可以使用的 DNS name
    image: # 镜像的名字
    command: # 可选,如果设置,则会覆盖默认镜像里的 CMD命令
    environment: # 可选,相当于 docker run里的 --env
    volumes: # 可选,相当于docker run里的 -v
    networks: # 可选,相当于 docker run里的 --network
    ports: # 可选,相当于 docker run里的 -p
  servicename2:

volumes: # 可选,相当于 docker volume create

networks: # 可选,相当于 docker network create

只是简单的看这些解释,你不可能学会yml文件的写法的,下面我们就以一个wordpress的镜像为例,制作yaml文件。

wordpress的yaml文件写法

用命令的写法:

docker container run -d -p 80:80 wordpress

yaml文件的写法:

version: "3.8"

services:
  my-wordpress:
    image: wordpress:latest
    ports:
      - 80:80

docker-compose版本说明

docker-compose语法版本:https://docs.docker.com/compose/compose-file/

打开这个网址,就会看到composeDocker版本的兼容关系表。比如3.8版本,要求Docker Engine的版本是19.03.0+

我们可以使用下面的命令查看当前电脑的版本。

# docker --version
Docker version 20.10.7, build f0df350

可以看到,我们现在的Docker版本是完全符合compose的,所以在yaml文件的最开始写version:”3.8“是没有问题的。

这里需要说的是 :Compose现在有两个主要版本Version3Version2。这两个版本的yaml写法也略有不同,但是基础语法是相同的。

27.[docker-compose]基础命令使用

有了yaml文件后,我们如何能启动一个容器,包括docker compose的一些基础命令需要我们学习一下。这节就讲解一下docker compose的基础命令学习。

docker compose 的yaml文件

上节课简单学习了yaml文件的简单编写,我们启动了一个wordpress的容器,并进行了端口的映射。yaml文件如下.

version: "3.8"

services:
  my-wordpress:
    image: wordpress:latest
    ports:
      - 80:80

有这个文件后,可以打开VSCode,然后打开VSCode中的终端。就可以输入docker compose命令了。

开启容器的命令

要学的第一个命令是用来开启容器的docker compose up, 当然docker compose有很多命令。

可以直接输入docker compose然后回车,就可以看到相关的一系列命令了。

uild       Build or rebuild services  convert     Converts the compose file to platform's canonical format  cp          Copy files/folders between a service container and the local filesystem  create      Creates containers for a service.  down        Stop and remove containers, networks  events      Receive real time events from containers.  exec        Execute a command in a running container.  images      List images used by the created containers  kill        Force stop service containers.  logs        View output from containers
  ls          List running compose projects
  pause       pause services
  port        Print the public port for a port binding.
  ps          List containers
  pull        Pull service images
  push        Push service images
  restart     Restart containers
  rm          Removes stopped service containers
  run         Run a one-off command on a service.
  start       Start services
  stop        Stop services
  top         Display the running processes
  unpause     unpause services
  up          Create and start containers

终端里输入下面的命令,就可以开启wordpress容器了。

docker compose up

但这时候的容器开启方式是有日志输出的,并且窗口被占用了。没办法进行其它操作了。可以加入-d参数,解决这个问题。

docker compose up -d

这样就是后台运行模式了,我们就可以继续操作这个终端了。如果你想查看service运行情况,可以使用下面的命令。

# docker-compose ps
       Name                      Command               State                Ports
-----------------------------------------------------------------------------------------------
test_my-wordpress_1   docker-entrypoint.sh apach ...   Up      0.0.0.0:80->80/tcp,:::80->80/tcp

注意这里是ps,而不是ls。要和普通的docker命令进行一个区分。

Docker compose的停止和清理

当你不在使用这个service的时候,就可以使用stop命令停止。

docker compose stop

停止以后,容器就处于Exited模式了。容器已经停止,就可以进行清理了。

docker compose rm

命令会删除掉由docker compose所建立的容器,但用docker命令创建的容器不会被删除,对应的网络也不会被删除。

命名规则

docker compose创建的容器,名字都会加入一个对应文件夹的名字,比如我在的文件夹叫做test,而我在yaml文件中起的名字是my-wordpress。最终容器的名字就是test_my-wordpress_1

这个前缀其实是可以改的,比如我们希望前缀加上jspang。就可以使用-p参数。

docker-compose -p jspang up -d

你也可以在yaml文件里指定这个名字,方法是使用contaner_name: xxx但是这样作就会完全省略前缀和后缀。

version: "3.8"

services:
  my-wordpress:
        container_name: jspang
    image: wordpress:latest
    ports:
      - 80:80

再重新启动,你会发现容器的前缀和默认的数字后坠都没有了。其实这样也不是很好,对以后的操作会造成一定的影响。我在工作中一般会先写好文件夹的名字,然后直接使用docker compose启动容器。

28.[docker-compose]镜像构建和拉取

上节我们学习了docker compose的创建、停止和删除。但上节课我们使用的wordpress镜像,是官方已经存在的镜像,所以可直接到https://hub.docker.com网站拉取就可以了。但是 如果镜像是我们自定义的Dockerfile,我们要如何设置那?

docker compose 自定义镜像构建

我们用Dockerfile拉去一个node的镜像,构建一个新的镜像。这里是学习,所以就不作其他的Dockerfile的复杂定义了,就用最简单的来进行模拟。

Dockerfile文件

FROM node:latest
CMD []

这时候我们的docker-compose.yml文件如下。

version: "3.8"

services:
  my-node:
    image: my-node:latest

这里的image: my-node:latest,是我们自己构建的镜像,但是目前还没有。如果用docker compose up 构建会直接报错。我们运行一下,可以看到下面的错误。

docker compose up
[+] Running 0/1
 - my-node Error                                                                                              4.6s
Error response from daemon: pull access denied for my-node, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

意思就是这个my-node镜像在网上找不到,仓库里没有。

可以修改docker-compose.yml文件,让docker先构建镜像,然后再启动容器。

修改后的docker-compose.yml文件

version: "3.8"

services:
  my-node:
    build: ./file

修改后,这时候再使用docker compose up命令,这时候就会先进行构建镜像,然后再开启容器。

给自定义镜像命名

这时候就不会报错了,也可以正常启动容器了。但是还是有问题的,用下面的命令查看镜像的名字。

# docker image ls
REPOSITORY     TAG       IMAGE ID       CREATED      SIZE
test_my-node   latest    edf569856ed9   2 days ago   907MB

镜像的名字是test_my-node,这并不是我们想的叫做my-node。继续修改docker-compose.yml文件,增加image属性。

version: "3.8"

services:
  my-node:
    build: ./file
    image: my-node:latest

在执行docker compose up 命令之前,可以执行下面的命令删除无用信息。

docker system prune -f  # 删除没有使用的容器
dockers image prune  -a  # 删除不使用的镜像 

然后再次输入下面的命令,启动容器

docker compose up

容器启动之后,你再使用docker image ls 会看到镜像的名字已经变成了设置的名字。

# docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
my-node      latest    edf569856ed9   2 days ago   907MB

这样就实现了用docker compose自动逸镜像的名字。

启动镜像前拉去镜像

上节课在docker compose中使用了wordpress的镜像。这个容器启动的时间是很长的,因为如果本地没有wordpress镜像,就要去官网上进行拉去,这个占用了95%以上的时间。这时候可以先使用下面的命令进行拉去镜像。

docker compose pull

拉去wordpress镜像的时间比较长,这里就演示拉去node 的了。修改docker-compose.yml文件。

version: "3.8"

services:
  my-node:
    image: node:latest

再使用docker image ls查看镜像列表,可以看到镜像已经被拉去到本地了。

总结:这节主要学习了自定义镜像Dockerfiledocker compose的结合操作,包括镜像构建、命名和拉取操作。

29:[网络]Docker的三种网络模式和Bridge网络模式讲解

这节课开始,学习一下Docker的网络模式。如果想要学好Docker,对网络的操作是绕不过去的。只有网络学好了,才能更深入的学习。比如Redis集群的搭建、Swarm的使用.....,都需要对网络模式有深刻的了解。

多容器的网络默认设置

一台服务器上可以跑很多容器,容器间是相互配合运行的。有配合就需要有网络通讯,就需要设置网络。

比如现在我们启动一个nginx的容器,用detached模式启动,并映射端口到80上。

docekr container run -d -p 80:80 nginx

容器启动后,可以用查看容器的具体信息。命令如下。

docker inspect <Container ID >

输入完成后,你可以看到有很多信息。其中有一项是Networks,这个就是容器的网路设置了。

"Networks": {
    "bridge": {
       "IPAMConfig": null,
       "Links": null,
       "Aliases": null,
       "NetworkID": "bd2fe52b4c98ec5c5a11131a0bec714035ae25c791a518f7302d7f02c0aa8a75",
       "EndpointID": "2b8e1ff95d9f0f56be7a9f3737a1a695f523c290aefcd8c5f08130b9fb4535df",
       "Gateway": "172.17.0.1",
       "IPAddress": "172.17.0.2",
        "IPPrefixLen": 16,
       "IPv6Gateway": "",
       "GlobalIPv6Address": "",
       "GlobalIPv6PrefixLen": 0,
       "MacAddress": "02:42:ac:11:00:02",
       "DriverOpts": null
         }
    }

信息中是可以看出很多东西的,比如这个网络的连接方式是bridge,也就是桥接。然后IP地址IPAddress172.17.0.2这个就是它的内网IP地址。

为了看的更清晰,我们可以再启动一个nginx容器.

docker container run -d -p 8080:80 nginx

这时候再使用docker inspect <Container ID >可以看到网络信息是下面这样的。

"Networks": {
    "bridge": {
        "IPAMConfig": null,
        "Links": null,
        "Aliases": null,
        "NetworkID": "bd2fe52b4c98ec5c5a11131a0bec714035ae25c791a518f7302d7f02c0aa8a75",
        "EndpointID": "4686cd198f9e6bbc22b25d1ce2b8e58dbadb60c6b20158a5afaf1bf2856bcdb3",
        "Gateway": "172.17.0.1",
        "IPAddress": "172.17.0.3",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "02:42:ac:11:00:03",
        "DriverOpts": null
    }
}

可以看到这个网络依然是桥接,IP地址变成了172.0.0.3.

也就是说每一个容器启动后都会有一个IP,并且每个IP是不同,自动变化的。这就是Docker为我们作的默认网络配置。并且虽然容器的启动顺畅,给的IP地址也是递增的。

这种默认的问题就是,如果每次启动的顺序不一样,IP地址就会不同,这样每次都要重新进行配置。这肯定在工作中是行不通的。真实工作中,可能一台服务器就有几十个容器,如果每次修改通讯地址,这个工作将变的混乱不堪,无法继续。

那一般情况下,我们会通过- -name来置顶固定名称,然后再用名称进行通信。这种解决方案的前提就是需要了解网络模式和自定义网络后,才能实现可控状态。

查看所有Docker的网络列表

可以使用下面的命令进行查看主机上已经有的网络配置列表.

docker network ls

如果你的主机 刚装好Docker,只有下面三种网络模式 名称:

  • bridge : 这个是网桥,我习惯性的说成桥接模式。为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,默认为该模式。
  • host :使用主机模式,容器没有IP和网关这些,都是用实体主机的。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
  • none :就是不创建自己的IP网络。也就是常说的没有网,当然你可以自己进行定义网络模式。容器有独立的Network namespace,但并没有对其继续任何网络设置,如分配veth pair 和网桥连接,IP等。
  • container : 就是利用其它容器的网络,别的容器有网络了,使用其它的容器网络。新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口等。此种方式不是默认网络模式,它需要基于另一个容器。

这些网络模式都会在后面的课程中讲解,所以不要着急。这节课我们主要讲解第一种网络模式Bridge模式.

bridge网络模式

在该模式中,Docker守护进程创建了一个虚拟以太网桥 docker 0,新建的容器会自动桥接到这个接口,附加在其上的任何网卡之间都能自动转发数据包。

默认情况下,守护进程会创建一对 对等虚拟设备接口 veth pair, 将其中一个接口设置为容器的eth0 接口(也就是容器的网络/网卡接口),另一个接口放置在主机的命名空间中,以类似vethxxx这样的名字命名,从而将主机上的所有容器都连接到这个内部网络上。

docker_bridge.jpeg

通过图可以清楚的看到桥接模式,eth0是主机网卡,docker0就是桥接网络,每个容器都有自己的teh0,然后通过docker0和主机进行通信,也形成了内部局域网。

用busybox查看网络

为了更好的理解Bridge模式,我们启动一个busybox的镜像。 然后查看一下网络。

busybox 被称为嵌入式Linux的瑞士军刀,整合了很多小的unix下的通用功能,并且只有一个很小的执行文件。

启动busybox的命令,这里使用了交互模式,并且给容器起了一个名字bbox01

docker run -it --name bbox01 busybox 

当这个容器启动后,新启动一个CentOS远程主机的会话,然后使用shell命令看一下现在主机网络会多出一个vethxxxxx的信息

ip  addr

然后再到busybox中查看网络信息,可以看出他们形成了一组网络配置。

通过这个案例,你再回来看上面那段话,就会有深刻的了解。其实就是通过一对 对等虚拟设备实现网络通信,也就是桥接模式。

总结:这节课我们主要学习了Docker网络相关的知识,也讲述了Docker常见的四种网络模式( bridge、host 、none、container),最后通过busybox容器,详细演示了一下bridge模式。

30.[网络]host和none网络模式讲解

这节课讲一下host模式和none模式。先来说host模式。

host网络模式

host网络模式使用主机网络模式,容器没有IP和网关这些,都是用实体主机的。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

  • 采用host网络模式的Docker Container,可以直接使用主机的IP地址与外界进行通信,若主机的eth0是一个共有IP,那么容器有用这个共有IP。同时容器内服务的端口也可以使用端口,无需额外进行NAT转换。

启动一个Nginx容器,这个容器的特点是不再使用默认的bridge模式,而是使用host模式。使用host模式的关键字是- - network host或者- - net host都可以

docker run -it --name nginx1 --network host nginx

启动后,可以打开浏览器,然后直接输入主机的IP地址,我的IP地址是110.40.130.171,就可以看到nginx提供的默认页面了。这时候使用的是主机的网络设置,并没有映射80端口

再重新打开一个终端,利用ip addr查看网络情况。这时候是没有桥接网络的,进一步证明了我们使用的是host模式。

[root@VM-0-12-centos ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:5d:20:c6 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.12/20 brd 172.17.15.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe5d:20c6/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:0b:ee:d6:93 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:bff:feee:d693/64 scope link 
       valid_lft forever preferred_lft forever

看起来使用host模式挺好,但是由于host网络模式可以让容器共享主机网络,虽然可以直接通信,但是容器的网络同样缺少隔离性。

none网络模式

none网络模式是指禁用网络功能,只有lo接口local的简写,代表127.0.0.1,既localhost本地环回接口。在创建容器时通过 - - net none或者--network none 指定。

创建一个busybox的容器,使用none的网络模式

docker run -it --name bbox02 --network none busybox

bbox02容器启动完成后,使用ip addr可以看到只有一个lo的网络。

/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever

这里的lo就是local,代表着只有本地地址,没有其他操作了。也就是没有网络状态,需要自己进行配置。

这时候有的小伙伴会问了。这种网络模式的用处是什么那?

none网络模式即不为Docker Container创建任何的网络环境,容器内部只能使用loopback网络设备,不会再有其他的网络资源。可以说none模式为Docker Container做了极少的网络设定,但是俗话说的好“少即是多”。在没有网络配置的情况下,作为Docker 开发者,才能在这基础做其他无限多的可能的网络定制开发。这也体现了Docker设计理念的开发。

好了,这节就到这里了,下节主要学习一下Container网络模式。

31.[网络]container网络模式使用

这节我们主要学习一下Container网络模式的设置方法和使用场景。

container网络模式

Container 网络模式是Docker中一种较为特别的网络模式。在创建时通过参数- - net container : 已运行的网络名称 | ID 或者- - network container : 已运行的容器名称 | ID 指定。

处于这个模式下的Docker容器会共享一个网络栈,这样两个容器之间可以使用localhost高效通信。Container网络模式即新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是隔离的。

为了更好的理解container网络模式,我们创建2个busybox的容器。第一个使用默认的桥接模式bridge,第二个使用container模式。

先来开启第一个容器,使用- -name给容器命名为bbox01

docker run  - it --name bbox01  busybox

第一个容器开启后,就会有一对 对等虚拟网络,也就是我们之前学到的桥接模式网络。可以新开一个窗口输入ip addr命令,查看这个虚拟网络。

第一个开启后,再用- - network container:bbox01开启第二个容器。

docker run -it --name bbox02 --network container:bbox01 busybox

容器创建好以后,在容器的交互模式下,使用ip addr查看,你会发现和bbox01容器中的网络是一样的。以此证明了bbox02使用了bbox01的网络。

这时候使用ping 命令,查看一下百度的地址,是完全可以ping通的。

主容器退出后,附容器无法联网

如果主容器退出以后,那么附容器将没办法联网,这里的的意思是依附于主容器。现在我们回到第一个shell窗口,然后使用exit退出bbox01容器。再回到第二个shell窗口,重新ping www.baidu.com,是没办法ping通的。

说明主容器退出后,附容器将没办法再继续使用。

再回到第一个shell窗口,启动bbox01容器。

docker container start bbox01

然后再回到第二个shell窗口,网络依然不可以使用,这时候你要重新启动容器后,才能再次进行使用。

先用exit命令退出容器,然后使用下面的命令重启。

docker container start bbox02

然后使用exec命令进入交互模式。

docker exec -it bbox02 sh

这时候在ping我的博客jspang.com就可以ping通了。

相信通过讲解和练习,你已经对docker 的container 网络模式有了解啦。这种网络模式也经常使用。可以多练习一下。下节我们继续学习了。

真诚感谢您的留言,我会亲自查收每一条留言并进行回复,审核后显示在文章底部。
您的昵称
电子邮件
最新留言

No Data

技术胖
光头Coder12年经验业余讲师免费视频被访问
文章目录