Docker:教你如何把服务器装进口袋里,让工资涨得明明白白(二)

1,850 阅读17分钟

本文正在参加「金石计划」

二、初体验

Docker并非是一个通用的容器工具,它依赖于Linux内核环境,Docker本质上是在已经运行的Linux下制造的一个隔离的文件环境,因此他执行的效率几乎等同于所部属的Linux主机,因此Docker必须部署在Linux内核的环境中,如果其他的系统想部署Docker就必须要安装一个Linux虚拟环境。

我们在Windows上部署Docker的方法都是先安装一个虚拟机,然后在虚拟机上运行Docker。

Docker 从 2013 年 3 月 20 日发布 Docker 0.1,到现在已经发布了多个版本,从 2017 年 3 月开始 docker 在原来的基础上分为两个分支版本: Docker CE 和 Docker EE。Dcoker有两种版本:

  1. Docker CE:社区免费版,可永久免费使用。
  2. Docker EE:企业版,功能更全,更强调安全,但需付费使用。

2.1、安装Docker

CentOS 仅发行版本中的内核支持 Docker。Docker 运行在CentOS 7 (64-bit)上,要求系统为64位、Linux系统内核版本为 3.8以上,这里选用Centos7.x。

安装Docker有两种方式:

  1. 官网命令安装。
  2. Bash脚本安装。

2.1.1、官网命令安装

首先我们先要去卸载原始的Docker。

yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

然后安装docker依赖

 yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2

指定yum源,

yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

最后再安装最新的版本的Docker。

yum install docker-ce docker-ce-cli containerd.io

我们先启动Docker。

sudo systemctl enable docker
sudo systemctl start docker

关闭Docker。

sudo systemctl stop docker

测试一下Docker是否安装成功了。

sudo docker run hello-world

但是好像这样安装有一点点繁琐。

2.1.2、Bash脚本安装

在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装,另外可以通过 --mirror 选项使用国内源进行安装:执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。

首先我们要下载Docker引擎的脚本文件。

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

然后我们就需要去执行我们的脚本,但是为了加速下载Docker,我们需要先指定一下阿里云镜像。

sudo sh get-docker.sh --mirror Aliyun

我们需要先将Docker加入开机自启动的列表。

sudo systemctl enable docker

然后启动Docker。

sudo systemctl start docker

这样就安装好了Docker。按照国际惯例,我们来检测一下Docker是否安装好了。

docker version

image-20230318155619389

我们可以发现,Docker分为两部分,一部分是客户端,一部分是服务端,他们分别有不同的版本。

  1. 服务端:客户端用于运行一个个的容器。
  2. 客户端:用户接受我们写的一个个的命令。,并且帮我们将命令发给我们的服务端。

2.1.3、配置阿里云镜像加速

阿里云大方的为我们每个人都独家配置了一份镜像加速,但是我们需要去申请。申请地址就是在阿里云官网。直接搜索容器镜像服务即可使用。

我们来看一下Docker官方文档对于镜像加速器的使用教程。

image-20230319125111505

我们来逐行解释一下这些配置。

首先我们先要在/etc下创建一个docker目录

 mkdir -p /etc/docker

再写入以下配置。

tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://f7p8y5t5.mirror.aliyuncs.com"]
}
EOF

image-20230319125628220

接着重启我们的Docker。

systemctl daemon-reload
systemctl restart docker

好像配置完了,又好像没有配置,我们来检测一下是否配置成功。我们来输入命令。

docker info

如果在最后的几行出现了你之前配置过的镜像加速的话就说明配置成功了。

image-20230319125930433

2.2、Docker核心概念

image-20200404111908085-0291323

2.2.1、镜像Image

一个镜像代表一个应用环境,他是一个只读的文件,如 mysql镜像、tomcat镜像、nginx镜像等。镜像运行一次就会生成一个服务,而这一个个的服务就叫容器。

2.2.2、容器Container

镜像每次运行之后就是产生一个容器,就是正在运行的镜像,特点就是可读可写。

2.2.3、仓库Repository

仓库是用来存放镜像的位置,类似于maven仓库,也是镜像下载和上传的位置。Docker在全世界范围内维护了一个仓库,专门用于存放镜像,这个仓库叫Docker Hub。

我们去瞅一眼。

image-20230318162542578

打了这种标签的表示是官方镜像,否则就是不是,我们以后要多用官方镜像。

2.2.4、本地仓库

用来存储在使用Docker过程中的相关镜像,我们不希望每次都去从中央仓库去下载镜像,所以我们会在本地保存一份镜像。

2.3、第一个Docker程序

dcoker为了让你能够快速的入门docker,还贴心的准备一个hello world程序,目的是为了让你能够快速入门docker。

docker  run hello-world

看到Docker版的hello world即表示运行成功。

image-20230319143254253

2.4、Docker的执行流程

image-20230319145415504

在跑完第一个docker的hello world程序后,我们就可以开始总结一下docker但是执行流程。我们先来了解一下docker run 命令的运行流程。

在输入docker run后,他的运行逻辑(类似maven):

  1. docker先会去本地找一下看看有没有这个镜像。
  2. 如果有的话就可以直接运行镜像,生成一个容器。
  3. 如果没有的话就会去中央仓库去下载镜像,然后再生成一个容器,这样下次运行的时候就可以直接打包成一个容器了。

三、docker常见命令

3.1、镜像的基本操作

我们要记住几个docker常见的几个命令:

  1. docker version用来查看docker客户端引擎和服务端引擎的命令
  2. docker info用来查看docker引擎的详细信息。
  3. docker --help用来查看docker的帮助信息。

再来看看image镜像相关的命令:

  1. docker image ls:查看当前本地的仓库存在哪些镜像。
  2. docker images:查看当前本地的仓库存在哪些镜像。

image-20230319150737812

看到了我们的老朋友hello world有没有,我们来解释一下每一列代表着什么。

image-20230319150916188

  • REPOSITORY:镜像名称
  • TAG:镜像版本
  • IMAGE ID:docker在维护镜像的时候,为每一个镜像提供了一个唯一标识,这个标识就是IAMEG ID。
  • CRESTE:官方构建镜像的事件(不是我们本地拉取镜像的事件),相当于镜像的生日。
  • SIZE:镜像大小。

我们定位一镜像的方式有两种:

  1. 使用唯一id或者唯一id的前几位。
  2. 使用镜像名称:版本号的方式来定位一个镜像。

我们在docker images的时候,发现有一堆的镜像,这个时候如果我们想专一,只关注某个镜像的时候,在docker images后面还可以跟上镜像的名称。

image-20230319162941580

当然,docker还有一种检索方式,那就是只列出id,我们可以使用这条命令:

docker images -q

image-20230319163517497

当然了,我们还可以联合起来使用,比如说我想找到列出所有tomcat的id,这个时候我们就可以使用这条命令:

docker images tomcat -q

如果我们想定位一个toncat8.0镜像,而且想用名字来定位的话,我们可以这样定位:tomcat:8.0

如果我们想下载一个镜像的话,可以使用docker pull 镜像名称(:版本号),比如docker pull redis,如果我们不加版本好的话,默认会拉取最新的镜像。这句话等同于docker pull:laster,拉取最新版本。

image-20230319152002117

如果我们想下载tomcat9.0的话,我们可以这样写。

docker pull tomcat:9.0

image-20230319152330394

当我们想去下载镜像的时候,我们又不知道有哪些版本,这个时候我们就需要去搜索镜像。docker提供了搜索命令。

docker search 镜像名

image-20230319154436026

我们输入了以后,发现docker search 镜像名的时候会发现,这条命令有点问题,他不可以像docker hub一样返回redis的所有版本给我,如果我们想看reids有哪些版本的时候,还得去docker hub中去搜索。这个命令常用语搜索看看这个镜像在仓库中是否存在,无法列出对应的版本。

这个时候有个问题,我的虚拟器中有很多没用的镜像,那么这个时候我们要如何删除这些没用的镜像呢?删除镜像的命令如:

docker image rm 镜像名:tag(镜像id)

比如说我想删除tomcat这个镜像,如果不加tag的话,默认删除最新的。这种删除属于正常删除,前提是只能删除没用运行过的容器,运行过的的容器是无法删除的。

image-20230319155829508

比如说我们删除最开始hello-world镜像,他竟然报错了。

image-20230319160622819

当然了也有强制删除,这个时候docker就不会管容器的死活了。

docker image rm -f

我们来试一下他的强制删除。

image-20230319160841376

发现确实是被删除了。

image-20230319161109252

3.2、容器的基本操作

3.2.1、查看容器状态

我们首先来查看一下docker引擎中正在运行的容器。

docker ps

image-20230320110637337

这说明我们目前没有正在运行的容器。既然没有正在运行的容器,那么我们就需要去启动一下容器。

docker run 镜像名(镜像id)

如果我们想要简单的运行一个tomcat9.0的容器,那么这条命令即可,我们会发现docker还是很智能的,如果你没有pull过这个镜像,他会自动帮你先pull下来再运行,我们先来看一个过时的运行语句,如果我们以这种方式去运行容器的话,容器内部是无法访问的,现在基本上不会有人用这种方式去启动

docker run tomcat:9.0

image-20230320111028222

这个时候我们克隆一个窗口,然后查看一下正在运行的容器。

image-20230320111215146

可以看到他确实是运行起来了。知其然知其所以然,所以我们来看看他的这一行都是啥意思。

  1. CONTAINER ID:容器id,每个容器在我们的docker里面也有一个唯一id标识,这个标识就是容器id。
  2. IMAGE:当前容器是基于哪个镜像运行的
  3. COMMAND:容器内启动该服务的命令
  4. CREATED:容器的创建时间
  5. STATUS:容器当前的状态
  6. PORTS:容器内该服务监听的端口
  7. NAMES:容器的名称

我们在运行的时候用外网访问的时候发现无法访问,这是因为docker起的容器确实是一个服务,但是他是操作系统层面的隔离,也就是说这个8080端口是在docker里面。也就是说我们以后运行容器的时候不可以用docker run直接运行,因为他是直接跑在自己的操作系统中,和外界是没有任何联系的,所以我们还差了一步,那就是端口映射,我们需要把docker内部的8080端口映射到自己的服务器(宿主机)的8080端口。

所以我们需要在运行容器的时候指定一下映射,我们需要用到-p这个参数。

docker run -p 宿主机端口:容器内服务端口 tomcat8.0

我们得先把刚刚启动的tomcat给关掉,不然会报端口占用的错误。

image-20230320114748049

我们会发现,每次我们起一个容器的时候都会需要占用一个小黑框,这个时候我们想能不能后台启动?

docker还有一个参数,-d表示以后台启动的方式来启动容器,这个时候他会返回容器的id给你。

image-20230320151830067

唯一确定一个容器不仅仅可以使用id,还可以使用容器的名字作为唯一的标识,如果我们不指定名字的话,docker会默认起一个随机的名字,我们在开发的时候尽量给容器起一个好听的名字,方便以后我们启动。docker也可以指定名字来进行启动。--name可以指定容器启动的名字。

image-20230320152412894

docker run -p 8080:8080 --name tomcat9 tomcat8.0

3.2.2、容器的启动与停止

如果我们需要重启一个容器的时候,可以使用这条命令,docker在接收到stop命令的时候还可以允许容器内部的服务去做一个正常关闭的操作。

docker stop 容器id(容器名称)

而和stop类似的命令有kill命令。

docker kill  容器id(容器名称)

当容器接收到kill命令的时候,是直接把容器的进程杀死,不允许容器做后续处理。开发中谨慎使用。

重启容器的命令。

docker restart 容器id(容器名称)

暂停一个容器的命令。

docker pause 容器id(容器名称)

既然有暂停那肯定就有恢复一个容器处于运行状态。

docker unpause 容器id(容器名称)

删除容器的时候,我们只需要记住容器的名字或者是容器id的前面几位,可以区别其他容器即可,但是rm命令只可以去删除已经停止运行的容器。

docker rm 容器id(容器名称)

如果我就是想删除一个正在运行的容器怎么办?可以使用这条命令来强制删除当前容器,无论这个容器处于什么状态。

docker rm -rf 容器id(容器名称)

如果想删除所有的容器的话可以使用这条命令。

docker rm -f $(docker ps -aq)

3.2.3、进入容器内部

如果我们想查看容器内部的日志的话,可以使用这条命令。

docker logs 容器id(容器名称)

这条命令有三个参数:

  1. -t:加入时间戳,如果不加-t的话,默认是显示docker容器的时间,这个时间和宿主机的时间是对不上的,如果加了-t显示的是宿主机的时间。
  2. -f:跟随打印最新的日志(实时打印)
  3. --tail 数字:显示最后的多少条

接下来是最重要的命令,那就是进入docker内部。之前说过docker内部是一个微型的操作系统,那么我们怎么证明呢?我们可以用这条命令进入容器。

docker exec -it 容器id(容器名称)bash

如果我们不加这两个参数的话,会提示我们这两个参数是必须的。

image-20230320214843374

我们进去容器内部看看是啥样!

image-20230320215235686

好像他的窗口名字确实和普通的Linux窗口不同。

image-20230320215309573

3.2.4、容器与宿主机的文件拷贝

bash参数的意思就是我们以交互的模式进入docker容器内部。如果我们想退出容器的话,使用exit指令即可。接下来我们要与容器做文件传输。我们现在想把容器里面的某个文件拷贝到宿主机上,docker也提供了命令,将容器内的资源拷贝到宿主机中。

docker cp 容器id:容器中的文件或者目录 拷贝到宿主机的哪个目录

我们来试一下拷贝的命令,把/usr/local/tomcat/logs目录拷贝到 /root/

docker cp 376:/usr/local/tomcat/logs /root/

image-20230320223034129

我们去宿主机中查看,发现确实有这个目录。

image-20230320223226168

cp命令不仅仅可以将容器内的东西往外面拷贝,如果我们想将主机的文件拷贝到docker容器内的话也可以。

docker cp 主机文件和目录 容器id:容器中的目录

3.2.5、查看容器内的进程

如果我们想查看容器内运行的进程的话,可以使用这条命令。

docker top 容器id(容器名称)

image-20230321095746021

如果我们想查看容器内的详细细节(比如网络相关配置),我们使用这条命令去查看。

docker inspect  容器id(容器名称)

3.2.6、容器数据卷

3.2.6.1、以绝对路径方式的方式设置数据卷

数据卷的作用是用来实现容器中的数据和宿主机的数据进行映射(同步)的。之前我们学过cp命令,但是我们会发现cp命令非常麻烦,每次都要复制,如果我们不想频繁的拷贝的话,我们可以使用数据卷,这个数据卷有点类似vue的双向数据绑定。

简单来说就是对容器的改变可以影响到宿主机,对于宿主机的改变同样可以影响到容器,需要注意的是数据卷的使用必须在容器手动启动时设置,容器启动后再设置数据卷的话就没有意义了。

使用数据卷也很简单,我们只需要在容器启动命令中加一个-v的选项即可。

docker run  -v 宿主机目录的绝对路径:容器内目录的绝对路径

同时也可以设置多个数据卷。

xxxxxxxxxx docker run  -v 宿主机的目录的绝对路径:容器内的目录绝对路径  -v 宿主机的目录的绝对路径:容器内的目录绝对路径

如果我们使用绝对路径来设置数据卷的话,会将容器绝对路径的目录全部清空,始终以宿主机的绝对路径为主,不建议使用这种。

我们还可以加一个参数表示只读,如果设置了这种方式的话代表日后容器内的路径是只读的。注意ro这个参数只可以加在容器的路径上,表示容器路径的改变不会影响宿主机,只可以宿主机的改变影响容器。

docker run  -v 宿主机目录的绝对路径:容器内目录的绝对路径:ro

3.2.6.2、以别名的方式设置数据卷

我们还可以以别名的方式来设置数据卷。他的语法长这样。

dicker run -v 数据卷的别名:容器内目录的绝对路径

如果这个数据卷别名已经存在的话,docker会直接使用,如果不存在的话docker会自动创建,我们使用别名的方式会保留容器内原始的路径的内容,前提是别名对应的路径不能存在。docker根据别名创建目录默认在/var/lib/docker/volumes

3.2.7、容器打包成镜像

一个镜像代表一个软件服务,镜像每运行一次就会生成一个容器,运行的容器代表正在运行的软件服务。我们可以把自己的容器打包成一个镜像,这样我们下次就可以直接拉取自己的镜像运行,因为镜像是可读可写的,所以如果我们打包成景象的话就可以对容器进行自己的深度定制。那么我们如何将容器打包成一新的镜像呢?

docker commit -m "描述信息" -a "作者信息"   容器id或者名称 打包的镜像名称:标签

image-20230321135841706

docker commit -m "this is my tomcat" -a "xiaolin" 376 tomcat-xiaolin:9.0

我现在把我本地的tomcat打包成一个镜像,但是注意打包的容器的名称不可以有大写字母,不然会报错。

image-20230321140000736

docker commit -m "this is my tomcat" -a "XiaoLin" 376 tomcat-XiaoLin:9.0

我们来看看docker的镜像,看看有没有打包好。

docker images

image-20230321140410490

3.2.8、镜像的备份与恢复

我们可以使用save指令来备份指令。

docker save 镜像名 -o  名称.tar

恢复镜像的指令如下。

docker load -i   名称.tar