Docker架构及使用

了解Docker

Docker是一个用来装应用的容器,就像杯子可以装水,笔筒可以放笔,书包可以放书,可以把hello word放在Docker中,可以把网站放入Docker中,可以把任何想得到的程序放在Docker中。

Docker的思想

集装箱

没有集装箱之前运输货物,东西零散容易丢失,有了集装箱之后货物不容易丢失,我们可以把货物想象成程序,目前我们要把程序部署到一台新的机器上,可能会启动不起来,比如少一些配置文件什么的或者少了什么数据,有了Docker的集装箱可以保证我们的程序不管运行在哪不会缺东西.

标准化

运输方式

Docker运输东西有一个超级码头,任何地方需要货物都由鲸鱼先送到超级码头,然后再由鲸鱼从超级码头把货物送到目的地去.对应的技术来说,比如我们要把台式机的应用部署到笔记本上,我们可能选择用QQ发过去或者用U盘拷过去,Docker就标准化了这个过程,我们只需在台式机上执行一个Docker命令,把鲸鱼派过来,把程序送到超级码头去,再在笔记本上执行一个Docker命令,然后由鲸鱼把程序从超级码头送到笔记本上去.

存储方式

当我们把程序存储到笔记本上时,我们需要一个目录,且我们要记住这个目录,因为下次我们可能还要修改,有了Docker之后我们就不用记住了程序在哪里了,我们使用的时候只需要一条命令就行了.

API接口

Docker提供了一系列rest api的接口,包含了对Docker也就是对我们的应用的一个启动停止查看删除等等,如当我们要启动tomcat时我们要执行startup命令,当我们要停止时要执行shutdown命令,如果不是tomcat,我们可能还需要一些别的命令.有了Docker我们记Docker的命令就可以对其进行操作.

隔离

我们在使用虚拟机时有自己的cpu,硬盘,内存,完全感觉不到外面主机的存在,Docker也差不多,不过它更轻量,我们创建虚拟机可能要几分钟,但是Docker只需要一秒.最底层的技术时linux一种内核的限制机制,叫做LXC,LXC是一种轻量级的容器虚拟化技术.最大效率的隔离了进程和资源.通过cgroup,namespace等限制,隔离进程组所使用的物理资源,比如CPU,MEMORY等等,这个机制在7,8年前已经加入到linux内核了,直到2013年Docker出世的时候才火起来,大家可能奇怪为什么这么好的技术埋没这么多年都没人发现呢?英雄造时势,时势造英雄,如果没有云计算,敏捷开发,高频度的弹性伸缩需求,没有IT行业这么多年长足的发展,也就没有Docker.

Docker解决的问题

系统环境的不一致

形象的来说,Docker将操作系统、应用程序、代码、配置全部打包放入一个集装箱里,再将其放在鲸鱼上,使用时再由鲸鱼送到服务器上,在我的机器上怎么运行,在别的机器上就怎么运行。(有点像Java的虚拟机,使用应用Docker虚拟负载一系列应用所需的资源来达到一致性)

Docker架构

在上面的学习中,我们简单地讲解了Docker的基本架构。了解到了Docker 使用的是 C/S 结构,即客户端/服务器体系结构。明白了 Docker 客户端与 Docker 服务器进行交互时, Docker 服务端负责构建、运行和分发 Docker 镜像。 也知道了Docker 客户端和服务端可以运行在一台机器上,可以通过 RESTful 、 stock 或网络接口与远程 Docker 服务端进行通信。
我们从下图可以很直观的了解到Docker的架构:

Docker 的核心组件包括:

  1. Docker Client
  2. Docker daemon
  3. Docker Image
  4. Docker Registry
  5. Docker Container

Docker 采用的是 Client/Server 架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。客户端和服务器可以运行在同一个 Host 上,客户端也可以通过 socket 或 REST API 与远程的服务器通信。可能很多朋友暂时不太理解一些东西,比如 REST API 是什么东西等,不过没关系,在后面的文章中会一一给大家讲解清楚。

Docker Client(与用户交互)

Docker Client ,也称 Docker 客户端。它其实就是 Docker 提供命令行界面 (CLI) 工具,是许多 Docker 用户与 Docker 进行交互的主要方式。客户端可以构建,运行和停止应用程序,还可以远程与Docker_Host进行交互。最常用的 Docker 客户端就是 docker 命令,我们可以通过 docker 命令很方便地在 host 上构建和运行 docker 容器。

Docker daemon(服务组件,调度进程)

Docker daemon 是服务器组件,以 Linux 后台服务的方式运行,是 Docker 最核心的后台进程,我们也把它称为守护进程。它负责响应来自 Docker Client 的请求,然后将这些请求翻译成系统调用完成容器管理操作。该进程会在后台启动一个 API Server ,负责接收由 Docker Client 发送的请求,接收到的请求将通过Docker daemon 内部的一个路由分发调度,由具体的函数来执行请求。

我们大致可以将其分为以下三部分:

  • Docker Server
  • Engine
  • Job

Docker Daemon的架构如下所示:

Docker Daemon 可以认为是通过 Docker Server 模块接受 Docker Client 的请求,并在 Engine 中处理请求,然后根据请求类型,创建出指定的 Job 并运行。 Docker Daemon 运行在 Docker host 上,负责创建、运行、监控容器,构建、存储镜像。
运行过程的作用有以下几种可能:

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

由于 Docker Daemon 和 Docker Client 的启动都是通过可执行文件 docker 来完成的,因此两者的启动流程非常相似。 Docker 可执行文件运行时,运行代码通过不同的命令行 flag 参数,区分两者,并最终运行两者各自相应的部分。
启动 Docker Daemon 时,一般可以使用以下命令来完成
docker --daemon = true docker –d docker –d = true
再由 docker 的 main() 函数来解析以上命令的相应 flag 参数,并最终完成 Docker Daemon 的启动。
下图可以很直观地看到 Docker Daemon 的启动流程:

默认配置下, Docker daemon 只能响应来自本地 Host 的客户端请求。如果要允许远程客户端请求,需要在配置文件中打开 TCP 监听。我们可以照着如下步骤进行配置:
1、编辑配置文件 /etc/systemd/system/multi-user.target.wants/docker.service ,在环境变量 ExecStart 后面添加 -H tcp://0.0.0.0,允许来自任意 IP 的客户端连接。

2、重启 Docker daemon
systemctl daemon-reload systemctl restart docker.service
3、我们通过以下命令即可实现与远程服务器通信
docker -H 服务器IP地址 info
-H 是用来指定服务器主机, info 子命令用于查看 Docker 服务器的信息

Docker Image(镜像)

Docker 镜像可以看作是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。我们可将 Docker 镜像看成只读模板,通过它可以创建 Docker 容器。
镜像有多种生成方法:

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

我们可以将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称作 Dockerfile ,通过执行 docker build 命令可以构建出 Docker 镜像。

Docker Registry(远程存储image的仓库)

Docker registry 是存储 docker image 的仓库,它在 docker 生态环境中的位置如下图所示:

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

Docker Container(运行示例,资源)

Docker 容器就是 Docker 镜像的运行实例,是真正运行项目程序、消耗系统资源、提供服务的地方。 Docker Container 提供了系统硬件环境,我们可以使用 Docker Images 这些制作好的系统盘,再加上我们所编写好的项目代码, run 一下就可以提供服务啦。

走进Docker

镜像就是上面说的集装箱,仓库就是超级码头,容器就是我们运行程序的地方.Docker运行程序的过程就是去仓库把镜像拉到本地,然后用一条命令把镜像运行起来变成容器.

  • build:构建,就是构建镜像.
  • ship:运输,运输镜像,从仓库和主机运输.
  • run:运行的镜像就是一个容器.
  • build,ship,run和镜像,仓库,容器是一一对应的.

镜像

前面我们讲到了集装箱,鲸鱼拖着的所有集装箱就是一个镜像.
从本质上来说镜像就是一系列文件,可以包括我们应用程序的文件,也可以包括我们应用的运行环境的文件,既然是文件,那么是以什么样的格式在本地保存的呢?
说到存储格式,就要提到linux的一个存储技术,叫做联合文件系统,是一种分层的文件系统,可以将不同的目录挂到同一个虚拟文件系统下.
比如在/home/tch的文件下还有test1,test2,test3三个文件,这三个文件中又有他们的一些子文件,

通过这种方式可以实现文件的分层,test1可以把它看作第一层,test2可以把它看作第二层,每一层有每一层自己的文件,Docker就是利用了这种分层的概念实现了镜像存储.
下图就是镜像的存储格式,这张图是分层的,最下面一层,上面也是一层层的好像集装箱罗列在一起.这就是镜像最直观的存储方式.下面是操作系统的引导,上面是linux操作系统,再上面是一些相关的软件,如果是我们自己的程序,就可以是tomcat,jdk,再往上是应用代码,每一层是我们自己都可以控制得,最上面一层先忽略不看,因为这是和容器有关的.注意一点,Docker镜像系统的每一层都是只读的,然后把每一层加载完成之后这些文件都会被看成是同一个目录,相当于只有一个文件系统.Docker的这种文件系统被称之为镜像.
20190524104102791.png

容器

为了便于理解,大家可以把容器想象成虚拟机,每个虚拟机都有自己的文件系统,可以把上图整个一部分看成是文件系统,与虚拟机系统的区别是这里面的文件系统是一层一层的,并且最下面的n层都是只读的,只有上面一层是可写的.为什么要有可写的这层呢?大家的程序运行起来,势必会要写一些日志,写一些文件,或者对系统的某一些文件做一些修改,所以容器在最上面一层创建了可读可写的文件系统.
在程序的运行过程中,如果要写镜像文件时,因为镜像的每一层都是只读的,它会把文件的每一层拷到文件的最上层,然后再对它进行修改,修改之后,当我们的应用读一个文件时会从顶层进行查找,如果没有才会找下一层.
由于容器的最上一层是可以修改的,镜像是不能修改的,这样就能保证镜像可以生成多个容器独立运行,没有任何干扰.

仓库

我们的镜像是要在其它机器上运行,如何进行传输呢?
这就用到了Docker仓库,我们要先把我们的镜像传到Docker仓库中,再由目的地把Docker仓库拉过去,这就完成了这样的一次传输过程.
谁提供了这样的仓库呢?Docker自己提供->hub.docker.com,但是在国内上网的话非常慢,为了解决这个问题,国内很多公司也在做自己的仓库.比较知名的是由网易蜂巢提供的 https://c.163yun.com/hub#/m/home/

Docker组件是如何协作运行容器

看到这里,我们已经对Docker基础架构已经熟悉的差不多了。现在我们再通过hello-world这个例子来体会一下 Docker 各个组件是如何协作的。
容器启动过程如下:

  • Docker 客户端执行 docker run 命令
  • Docker daemon 发现本地没有 hello-world 镜像
  • daemon 从 Docker Hub 下载镜像
  • 下载完成,镜像 hello-world 被保存到本地
  • Docker daemon 启动容器

具体过程可以看如下这幅演示图:

我们可以通过docker images 可以查看到 hello-world 已经下载到本地

我们可以通过docker ps 或者 docker container ls 显示正在运行的容器,我们可以看到, hello-world 在输出提示信息以后就会停止运行,容器自动终止,所以我们在查看的时候没有发现有容器在运行。

大体可以知道 Docker 组件协作运行容器可以分为以下几个过程:

  1. Docker 客户端执行 docker run 命令
  2. Docker daemon 发现本地没有我们需要的镜像
  3. daemon 从 Docker Hub 下载镜像
  4. 下载完成后,镜像被保存到本地
  5. Docker daemon 启动容器

Centos下Docker安装

查看内核版本

Docker 要求 CentOS 系统的内核版本高于 3.10,查看本页面的前提条件来验证你的CentOS 版本是否支持 Docker 。

[tch@localhost ~]$ uname -r
3.10.0-1160.66.1.el7.x86_64

卸载原有的Docker

[tch@localhost ~]$ yum remove docker \
           docker-client \
           docker-client-latest \
           docker-common \
           docker-latest \
           docker-latest-logrotate \
           docker-logrotate \
           docker-engine
已加载插件:fastestmirror, langpacks
您需要 root 权限执行此命令。
-------------------------------------------更换使用root账户或者是sudo进行操作
[tch@localhost ~]$ sudo yum remove docker \
>            docker-client \
>            docker-client-latest \
>            docker-common \
>            docker-latest \
>            docker-latest-logrotate \
>            docker-logrotate \
>            docker-engine
[sudo] tch 的密码:
已加载插件:fastestmirror, langpacks
参数 docker 没有匹配
参数 docker-client 没有匹配
参数 docker-client-latest 没有匹配
参数 docker-common 没有匹配
参数 docker-latest 没有匹配
参数 docker-latest-logrotate 没有匹配
参数 docker-logrotate 没有匹配
参数 docker-engine 没有匹配
不删除任何软件包

上网查看了其他的卸载方法:

#########杀死docker有关的容器###########################
[root@localhost tch]# docker kill $(docker ps -a -q)
#########删除所有docker容器#############################
[root@localhost tch]# docker rm $(docker ps -a -q)
#########删除所有docker镜像#############################
[root@localhost tch]# docker rmi $(docker images -q)
#########停止 docker 服务###############################
[root@localhost tch]# systemctl stop docker
####删除docker相关存储目录(分别进行执行以下四个命令)#####
[root@localhost tch]# rm -rf /etc/docker
[root@localhost tch]# rm -rf /run/docker
[root@localhost tch]# rm -rf /var/lib/dockershim
[root@localhost tch]# rm -rf /var/lib/docker
#########查看系统安装的Docker包##########################
[root@localhost tch]# yum list installed | grep docker
containerd.io.x86_64                    1.6.6-3.1.el7                  @docker-ce-stable
docker-ce.x86_64                        3:20.10.17-3.el7               @docker-ce-stable
docker-ce-cli.x86_64                    1:20.10.17-3.el7               @docker-ce-stable
docker-ce-rootless-extras.x86_64        20.10.17-3.el7                 @docker-ce-stable
docker-compose-plugin.x86_64            2.6.0-3.el7                    @docker-ce-stable
docker-scan-plugin.x86_64               0.17.0-3.el7                   @docker-ce-stable
#########删除系统安装的Docker包##########################
[root@localhost tch]# yum remove containerd.io.x86_64 docker-ce.x86_64 docker-ce-cli.x86_64 docker-ce-rootless-extras.x86_64 docker-compose-plugin.x86_64 docker-scan-plugin.x86_64
已加载插件:fastestmirror, langpacks
正在解决依赖关系
--> 正在检查事务
---> 软件包 containerd.io.x86_64.0.1.6.6-3.1.el7 将被 删除
---> 软件包 docker-ce.x86_64.3.20.10.17-3.el7 将被 删除
---> 软件包 docker-ce-cli.x86_64.1.20.10.17-3.el7 将被 删除
---> 软件包 docker-ce-rootless-extras.x86_64.0.20.10.17-3.el7 将被 删除
---> 软件包 docker-compose-plugin.x86_64.0.2.6.0-3.el7 将被 删除
---> 软件包 docker-scan-plugin.x86_64.0.0.17.0-3.el7 将被 删除
--> 解决依赖关系完成
base/7/x86_64                                                   | 3.6 kB  00:00:00     
docker-ce-stable/7/x86_64                                       | 3.5 kB  00:00:00     
extras/7/x86_64                                                 | 2.9 kB  00:00:00     
updates/7/x86_64                                                | 2.9 kB  00:00:00
#########删除完毕的检查################################
[root@localhost tch]# yum list installed | grep docker
[root@localhost tch]# docker -v
bash: /usr/bin/docker: 没有那个文件或目录

安装依赖

[root@localhost tch]# yum install -y yum-utils \
> device-mapper-persistent-data \
> lvm2
已加载插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
软件包 yum-utils-1.1.31-54.el7_8.noarch 已安装并且是最新版本
软件包 device-mapper-persistent-data-0.8.5-3.el7_9.2.x86_64 已安装并且是最新版本
软件包 7:lvm2-2.02.187-6.el7_9.5.x86_64 已安装并且是最新版本
无须任何处理

这里我事先已经安装过了,所以提示我已经安装了最新版本

安装Docker

Docker 软件包已经包括在默认的 CentOS-Extras 软件源里。因此想要安装 docker,只需要运行下面的 yum 命令

[root@localhost tch]# yum install docker

后续确认即可

检查Docker版本

[root@localhost tch]# docker -v
Docker version 1.13.1, build 7d71120/1.13.1

启动Docker并将其设置为开机自启

[root@localhost tch]# systemctl start docker
[root@localhost tch]# systemctl enable docker

Docker指令初使用

将远程仓库的镜像拉取到本地

docker pull [options] NAME[:TAG]

拉取hello-world镜像

[root@localhost tch]# docker pull library/hello-world
Using default tag: latest
Trying to pull repository docker.io/library/hello-world ... 
latest: Pulling from docker.io/library/hello-world
2db29710123e: Pull complete 
Digest: sha256:53f1bbee2f52c39e41682ee1d388285290c5c8a76cc92b42687eecf38e0af3f0
Status: Downloaded newer image for docker.io/hello-world:latest
  • NAME是拉取镜像的名称
  • TAG表示是可选的,如果不选表明时为latest,如果选择表明是指定版本的
  • options是拉取时的一些参数
  • 当不加请求地址的时候回去docker的官网拉取镜像

查看Docker中存在的镜像

docker images [options] [REPOSITORY[:TAG]]
[root@localhost tch]# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
docker.io/hello-world   latest              feb5d9fea6a5        9 months ago        13.3 kB

options是选项,后面是指定镜像的名称.这个用的不多,可能当本地镜像非常多的时候要指定查看某一个镜像
IMAGE ID 其实是一个64位的字符串,它可以唯一标识我们的镜像,这里只显示了16位,后面的被截掉了

运行指定的镜像

docker run [options] IMAGE[:TAG] [COMMAND] [ARG..]
  • IMAGE是镜像的名字
  • COMMAND是运行起来的时候要执行什么命令
  • ARG表示这条命令运行需要的参数

运行hello-world镜像

[root@localhost tch]# docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

输出这段提示以后,hello world 就会停止运行,容器自动终止。有些容器不会自动终止,因为提供的是服务,比如Mysql镜像等。
Docker 提供了一套简单实用的命令来创建和更新镜像,我们可以通过网络直接下载一个已经创建好了的应用镜像,并通过 Docker RUN 命令就可以直接使用。当镜像通过 RUN 命令运行成功后,这个运行的镜像就是一个 Docker 容器啦,容器可以理解为一个轻量级的沙箱, Docker 利用容器来运行和隔离应用,容器是可以被启动、停止、删除的,这并不会影响 Docker 镜像。

Docker的权限与工作目录问题

在 下有一个test.py,那么我想使用Docker下的Python镜像去运行这个test.py应该怎么做呢?
由于自己是零基础,也算是走了很多弯路。

工作目录问题

Docker是应该设置一个工作目录的,由于Docker可以形象的认作成一个虚拟机,那么我们的实体机与虚拟机其实算是隔离了的,所以实际上Docker是不能访问到我们实体机上的文件的。
如果要像我这样傻乎乎的直接访问实体机上的文件数据,那么,恭喜你,可以直接报错了。

那么我们应该如何执行这一个文件呢,在这里引入一个挂载的概念
无标题.png
那么指令是什么呢

-v 真实物理机的目录:挂载在容器的目录

但是设置了这个,还是不行,我们只是挂载把物理机的资源挂载在了虚拟机上,但是我们并没有设置我们的工作目录,也就是说docker并不知道命令从哪里开始执行,所以直接上指令

-w 容器的工作目录

容器权限读取问题

所以知道了如何将目录挂载在虚拟机上,那么我们开始python的工作吧!

[root@localhost python_test]# docker run \
-v /home/tch/python_test/:/usr/src/python \##挂载的位置
-w /usr/src/python  \##工作目录
python  \##使用的镜像
python test.py  \##使用的指令


咦?现在我们发现显示权限问题,我们的访问被拒绝了,让我看看这个文件的属于者是谁。

原来,我们如果使用Docker的默认权限去执行,那么权限肯定是不够的,所以我们直接使用root大法。

-u=用户  ##使用某一用户的权限运行Docker


但是即使是这样,还是不行,那么,上绝招

--privileged=true  ##使用该参数,container内的root拥有真正的root权限。


嘿嘿,这样就好了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值