《前端运维》三、Docker–1镜像与容器

一、基本概念

  如果我们想要让软件运行起来,首先要保证操作系统的设置,其次还需要依赖各种组件和库的正确安装。那么虚拟机就是一种带环境安装的一种解决方案,它可以实现在一种操作系统里面运行另外一种操作系统,但是虚拟机的缺点也是十分明显的,资源占用多、冗余步骤多、启动速度慢。由于虚拟机存在的这些令人诟病的缺点。Linux发展出了另一种虚拟化技术,Linux Containers,即Linux容器,缩写为LXC。

  Linux容器并没有虚拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一层保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。Linux的容器也十分明显,体积小、启动快、资源占用也是极少的。

  Docker属于Linux容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的Linux容器解决方案。Docker将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里面运行,就好像在真实的物理机上运行一样。

  同时Docker的应用场景也十分广泛,比如:单项目打包、整套项目打包、新开源技术、环境一致性、持续集成、微服务、弹性伸缩等。

  下面我们来看一张图,来学习下Docker体系的结构:

  我们看上图哦,Docker通过Docker Client的客户端发送指令,驱动Docker Engine引擎来启动容器,然后通过Containerd来管理对应容器的内容,然后,shim只用来管理每个独立的容器,通过runC这个轻量级的工具来启动容器。在启动容器的时候,可能会去Image Repository镜像仓库中去取对应的依赖。

  Docker提供了一些内部的组件,我们也需要了解一下:

  • namespaces,命名空间,Linux内核提供的一种对进程资源隔离的机制,例如进程、网络、挂载等资源。
  • cgroups,控制组,linux内核提供的一种限制进程资源的机制,例如cpu、内存等资源。
  • unonFS,联合文件系统,支持将不同位置的目录挂载到同一虚拟文件系统中,形成一种分层的模型。

二、Docker安装

  首先docker的版本类型上,分为企业版和社区版,咱们用社区版就可以了,企业版是付费的。它的安装文档地址在:https://docs.docker.com/engine/install/centos/

  我们通过下面的命令来安装下docker:

  先安装docker的一些依赖:

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

  再安装docker的安装源:

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

  最后安装docker:

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

  这样,我们的docker就安装好了。然后我们看下常用的一些命令:

# 启动docker
systemctl start docker

查看docker信息

docker version
docker info

卸载docker

yum remove docker

删除docker相关的文件夹

rm -rf /var/lib/docker

  我们也可以把相关的软件依赖改成阿里云的镜像地址,这样下载的时候会快一些,我就不多说了,因为我没改:

# 创建一个文件
sudo mkdir -p /etc/docker

写入一些配置

sudo tee /etc/docker/daemon.json <<-‘EOF’
{
“registry-mirrors”: [“https://fwvjnv59.mirror.aliyuncs.com"\]
}
EOF

重载所有修改过的配置文件

daemon-reload: 重新加载某个服务的配置文件

sudo systemctl daemon-reload
sudo systemctl restart docker

三、Docker镜像

   Docker把应用程序及其依赖,打包再image镜像文件里面,只有通过这个文件,才能生成Docker容器。image镜像文件可以看作是容器的模板。Docker根据image镜像文件生成容器的实例。同一个image镜像文件,可以生成多个同时运行的image实例。镜像文件不是一个单一的文件,而是有多层次的结构。容器其实就是在image镜像的最上面一层加了一层读写层。在运行容器里做的任何文件改动,都会写到这个读写层里。如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。

  我们可以通过docker history [id/name] 查看镜像中各层级的内容及大小,每层对应着dockerfile中的一条指令。

  下面我们来学习下一些基本的命令:

  1. docker image ls,查看全部镜像。字段含义如下: REPOSITORY 仓库地址 TAG 标签 IMAGE_ID 镜像ID CREATED 创建时间 SIZE 镜像大小
  2. docker search [imageName],查找镜像。字段含义如下: 字段 含义 NAME 名称 DESCRIPTION 描述 STARTS 星星的数量 OFFICIAL 是否官方源
  3. docker history [imageName],查看镜像历史。
  4. docker inspect [imageName],显示一个或多个镜像信息。
  5. docker pull [imageName],拉取镜像。
  6. **docker push [imageName],推送一个镜像到镜像仓库。******
  7. ****docker rmi [imageName],删除镜像。****
  8. **docker image prune,移除未使用的镜像,没有标记或被任何容器引用。******
  9. **tag,标记本地镜像,将其归入某一仓库******
    • **语法:docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]。******
    • **例子:docker tag centos:7 zaking/centos:v1。******
  10. **export,将容器文件系统作为一个tar归档文件导出到STDOUT。******
    • **语法:docker export [OPTIONS] CONTAINER。******
    • **docker export -o hello-world.tar b2712f1067a3。******
  11. **import,导入容器快照文件系统tar归档文件并创建镜像。******
    • **语法:docker import [OPTIONS] file/URL/- [REPOSITORY[:TAG]。******
    • **例子:docker import hello-world.tar。******
  12. **save,将指定文件保存成tar文件。******
    • **语法:docker save [OPTIONS] IMAGE [IMAGE…]。******
    • **docker save -o hello-world.tar hello-world:latest。******
  13. **load,加载tar文件并创建镜像。******
    • **例子:docker load -i hello-world.tar。******
  14. **build,根据Dockerfile构建镜像。******
  • **语法:docker build [OPTIONS] PATH / URL / -。******
  • **例子:docker build -t zf/ubuntu:v1。******

  然后,我们学习了一些相关的命令,下面我们来拿这些命令做一些实践:

  首先,我们查找一下centos镜像:

docker search centos

  然后,我们把centos的镜像拉取到本地,如果你这里下载很慢的话,请回头安装阿里源,嘻嘻:

docker pull centos

  然后,我们可以使用fs命令,查看下现在有哪些镜像:

docker image ls

  下一步我们从远程镜像仓库拉取一个docker官方的例子镜像到本地的镜像仓库:

docker pull docker.io/hello-world

  然后,可以通过rmi命令,删除本地镜像:

docker rmi hello-world

四、Docker容器

   首先,我们来学习下一些有关于容器的基本概念。docker run 命令会从image镜像文件中生成一个正在运行的容器实例。该命令具有自动抓取image镜像文件的功能,如果发现本地没有指定的image文件,就会从仓库自动抓取。输出提示后,实例就会停止运行,容器自动终止,当然,并不是所有的容器都会自动终止。同过image镜像文件生成的生成的容器实例,本身也是一个文件,成为容器文件。生成了容器后,就会同时存在两个文件,image镜像文件和容器文件。关闭容器并不会删除容器文件,只是停止容器的运行。

  下面,我们来学习一下容器有关的命令:

  1. docker run:启动容器。

    • 例子:docker run ubuntu /bin/echo ‘hello world’。这句话的意思就是,通过ubuntu镜像生成一个容器,在容器中执行/bin/echo ‘helloworld’的命令。我们看下图,当我们想要执行的命令在容器中打印后,该容器就自动终止了。这就是我们上面说到的含义。另外,如果本地没有对应的镜像,docker会自动去docker hub拉取。
    • 参数:
      • -i,–interactive:交互式。
      • -t,-tty:分配一个伪终端。
      • -d,–detach:运行容器到后台。
      • -a,–attach list:附加到运行的容器。
      • -e,–env list:设置环境变量。
      • -p,–publish list:发布容器端口到主机。
      • -P,–publish-all:。
  2. docker ps:查看容器。

    • 参数:
      • -a:显示所有的容器,包括已停止的。
      • **-l:显示最新的那个容器。****** 字段 含义 CONTAINER ID 容器ID IMAGE 使用的镜像 COMMAND 使用的命令 CREATED 创建时间 STATUS 状态 PORTS 端口号 NAMES 自动分配的名称
  3. docker run -i -t ubuntu /bin/bash:运行交互式的容器。可以通过exit命令或CTRL+D退出交互界面。

    • -t=–interactive 在新容器内指定一个伪终端或终端。
    • -i=–tty 允许你对容器内的标准输入 (STDIN) 进行交互。
  4. docker kill:kill是不管容器同不同意,直接执行kill -9,强行终止;stop的话,首先给容器发送一个TERM信号,让容器做一些退出前必须的保护性、安全性操作,然后让容器自动停止运行,如果在一段时间内,容器还是没有停止,再进行kill -9,强行终止。

    • 例子:docker kill 5a5c3a760f61。
  5. docker rm:删除容器

    • 例子:docker rm 5a5c3a760f61。
    • docker rm $(docker ps -a -q)。删除所有的容器,-a,所有的,-q显示id号。就是批量删除所有的意思。
  6. docker start [containerId]:启动容器

  7. docker stop [containerId]:停止容器。

  8. docker attach [containerID]:进入一个容器。

  9. docker container -exec -it [containerID] /bin/bash:进入一个正在进行中的容器。

  10. docker container cp [containerID]/readme.md .:拷贝文件。

  11. docker run –rm ubuntu /bin/bash:自动删除。

  12. docker container stats:显示容器资源使用统计。

  13. docker container top:显示一个容器运行的进程。

  14. docker update -m 500m 6d1a25f95132:更新一个或多个容器配置。

  15. **列出指定的容器的端口映射:******

    docker run -d -p 8080:80 nginx
    docker container port containerID 

  16. docker logs [containerId]:查看docker容器的输出。

  下面,我们把上面学习的命令来实践一下:

  刚才我们在学习run命令的时候已经启动了一个容器并打印出了命令,那个是最基础的方法,那下面,我们来查看下我们的容器都有哪些:

docker ps -a

   哈,只有一个,就是我们刚才执行的那个。下面我们来试一下启动一个交互式的容器:

docker run -i -t ubuntu /bin/bash 

  我们就进入了交互式容器的伪终端里,可以进行命令交互。然后我们执行下面的命令:

docker run centos ping www.baidu.com

  执行了这个命令后,就会一直ping www.baidu.com,别的事就干不了了,只能看着:

  此时,我们就需要–detach参数,进入后台运行:

docker run –detach centos ping www.baidu.com

  然后,这个容器就会在后台运行:

   那,我想要查看这个容器里面的日志怎么办呢,通过下面的命令就可以查看对应容器里的日志了:

docker logs –follow [id/name]

  当然,我们也可以通过attach,重新进入这个容器。

docker attach [id]

  然后,可以通过stop命令,停止某个正在运行中的容器:

docker stop [containerId]

   docker stop是否能停止,是由容器内部指定的,需要运行完一些必要的容器才会停止。如果你希望可以立即杀死该容器,直接强行终止,就使用kill命令。停止了以后,我们可以通过docker start来重新启动。

  然后,我们可以通过rm命令,删除已有的容器:

docker ps -a

  先通过ps命令看下目前容器的id,然后通过rm删除:

docker rm [id]

  这样一个一个删除太慢了,我们可以通过下面的命令批量删除:

docker rm $(docker ps -a -q)

  很简单吧。

1、其它命令实践:

  下面我们来练习下其他命令,我们先启动个hello-world的容器:

docker run hello-world

  然后我们把这个容器导出:

docker export -o hello-world.tar [cantainerId]

  然后我们看下这个文件:  

   删除这个容器:

docker rm [containerId]

  然后镜像文件也删除掉:

docker rmi hello-world

   然后,我们可以通过import命令,把刚才导出的tar包,再导入回来:

docker import hello-world.tar

   就是这个了。

   save命令可以把指定镜像打包成tar文件:

docker save -o redis.tar redis:latest

  然后删除你刚才打包成tar的镜像,怎么删除我就不说了啊。删除了之后,我们可以通过load命令,把刚才的tar包下载回来。

docker load -i redis.tar

  用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器(import)快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像(load)存储文件将保存完整记录,体积也要大。此外,从容器(import)快照文件导入时可以重新指定标签等元数据信息。

 2、下面我们来实践一些容器相关的:

  我们先后台跑起来前面的那个ping命令:

docker run –detach centos ping www.baidu.com

  然后,我们来用stats看下它的状态:

docker stats [containerId]

   然后可以通过top命令,查看一个运行中容器的进程:

docker top [containerId]

   我们还可以使用update命令更新一个或多个容器的配置,看stats那个图,LIMIT是1.7G左右,我们来通过update命令,限制一下它的内存:

docker update -m 500m [containerId]

   可惜报错了,他跟你说还要同时设置memoryswap,设置一下呗:

   然后LIMIT就变成了500M,简单吧。

3、下面我们来实践下如何映射指定容器的端口:

  先使用下面的命令,启动一个docker容器中的nginx:

docker run -d -P nginx

  这样会自动指定与宿主机的端口映射。

   图中红框的部分就是自动指定的与宿主机的映射,我们也可以手动设置:

docker run -d -p 8080:80

   这个意思就是说宿主机的ip是8080端口映射到docker容器的nginx的80端口。

4、学习下如何commit命令制作个性化镜像:

  我们先停止并删除之前所有的容器:

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

  然后像之前的例子一样,启动一个nginx容器。

  通过下面的命令进入到容器的伪终端中:

docker exec -it [containerId]/bin/bash

  然后,我们进入到容器的nginx存储html文件的目录,/usr/share/nginx/html:

cd /usr/share/nginx/html

  创建一个html文件:

echo hello > hello.html

  然后我们再打开一个命令行,访问一下刚才的nginx服务,要注意查看端口号哦:

   这样就成功了。下面看下如何基于这个容器,建一个新的镜像:

docker commit -m’zakings nginx’ -a’zaking’ 0a90e57ca86b zaking/zakingnginx

  这段代码是什么意思呢,docker commit -m’描述信息’ -a’作者信息’ [containerId] [包名]。

   我们可以查看下:

   多了我们刚才生成的镜像。下面我们清空下容器,使用我们自己创建的镜像创建容器:

   不多说了,实践好多遍了。

  然后呢,实际上就是跟之前的方式一样,创建nginx容器,并自动设置端口号就好了:

docker run -d -P [你自己刚才生成的镜像名字]

   然后,在另一个终端访问下:

   直接就出来了,不需要我们再重新创建了。当然,如果要发布到远程仓库,需要注册账号。这个我就不多说了,大家有兴趣可以自己试一下。

  好啦,关于容器和镜像的部分。就先到这里了。

站在巨人的肩膀上,希望我可以看的更远。