docker入门

前言
最近几年docker技术特别火,在各大互联网公司招聘要求上都会写这么一项“熟悉docker,k8s相关技术”。我网上搜了一下,原来docker早在2013年已经发布,由golang语言开发的现象级项目。那么,docker到底是什么东西,容器技术是怎样的,他能解决什么样的问题?带着这些问题,本文为你一步步揭开docker神秘的面纱。

一.docker介绍

1.1 docker是如何产生的

作为服务器开发人员,我们通常会遇到这样的很头疼的问题:明明代码在我本地跑没问题,怎么部署到线上就一大堆报错?由于本地代码需要安装各种软件,引入不同版本的代码库,我们必须一一罗列出来交给运维的同事,稍有不慎代码就报错。当项目扩容或者迁移的时候,同样的工作我们又要做一遍。这对于一个项目部署在几十成百上千台机器的运维人员来说简直是个灾难。那能不能把整个系统打包拷贝下来,等下次要再部署的时候直接安装整个包,就像我们把windows系统镜像拷贝到u盘需要装系统的时候直接使用这个ios镜像文件?

1.2 虚拟机技术

最早的时候人们发明了虚拟机,它可以在一种操作系统里面运行另一种操作系统,比如在 windows 系统里面运行 linux 系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。我们常用的VMware , VisualBox就是这种带环境安装的解决方案,但这种方案有几个缺点。

(1)资源占用多

虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有 1MB,虚拟机依然需要几百 MB 的内存才能运行。

(2)冗余步骤多

虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。

(3)启动慢

启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。

1.3 docker介绍

基于虚拟机技术以上的缺点,linux 发展出了另一种虚拟化技术:linux 容器(Linux Containers,缩写为 LXC)。docker 属于 linux 容器的一种封装,提供简单易用的容器使用接口,它是目前最流行的 linux 容器解决方案。Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。该方案有以下优点:
(1)资源占用少

容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。

(2)体积小

容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。

(3)启动快

容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,启动快速属于秒级别。

而且,docker提供了更加简单的交互接口,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。

1.4 docker的三个基本概念

学习docker要掌握三个基本概念:Image(镜像),Container(容器),Repository(仓库)。下图为三者之间的关系:

1.4.1 Image(镜像)

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

镜像不包含任何动态数据,其内容在构建之后也不会被改变。镜像(Image)就是一堆只读层(read-only layer)的统一视角,也许这个定义有些难以理解,下面的这张图能够帮助读者理解镜像的定义:

从左边我们看到了多个只读层,它们重叠在一起。除了最下面一层,其他层都会有一个指针指向下一层。这些层是 Docker 内部的实现细节,并且能够在主机的文件系统上访问到。统一文件系统(Union File System)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角。这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。我们可以在图片的右边看到这个视角的形式。

Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image。

1.4.2 Container(容器)

容器(Container)的定义和镜像(Image)几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。

由于容器的定义并没有提及是否要运行容器,所以实际上,容器 = 镜像 + 读写层。

1.4.3 Repository(仓库)

Docker 仓库是集中存放镜像文件的场所。镜像构建完成后,可以很容易的在当前宿主上运行。

但是, 如果需要在其他服务器上使用这个镜像(也可以通过命令直接导出),我们就需要一个集中的存储、分发镜像的服务,Docker Registry(仓库注册服务器)就是这样的服务。Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。

有时候会把仓库(Repository)和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,一个 Docker Registry 中可以包含多个仓库(Repository),每个仓库可以包含多个标签(Tag),每个标签对应着一个镜像。所以说,镜像仓库是 Docker 用来集中存放镜像文件的地方,类似于我们之前常用的代码仓库。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。

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

仓库又可以分为两种形式:

  • Public(公有仓库)
  • Private(私有仓库)

Docker Registry 公有仓库是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。当用户创建了自己的镜像之后就可以使用 Push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 Pull 下来就可以了。

我们先从下图可以直观地看到 Docker 的架构,后面再对其原理做详细介绍:

二. docker使用

2.1 安装及使用

Docker 是一个开源的商业产品,有两个版本:社区版(Community Edition,缩写为 CE)和企业版(Enterprise Edition,缩写为 EE)。企业版包含了一些收费服务,个人开发者一般用不到。下面的介绍都针对社区版。Docker CE 的安装请参考官方文档。
Mac
Windows
Ubuntu
Debian
CentOS
Fedora
其他 Linux 发行版

我们在安装前可以参看官方文档获取最新的 Docker 支持情况,官方文档
Docker 对于内核支持的功能,即内核的配置选项也有一定的要求(比如必须开启 Cgroup 和 Namespace 相关选项,以及其他的网络和存储驱动等)。Docker 源码中提供了一个检测脚本来检测和指导内核的配置,脚本链接

这里我们以 CentOS 7 作为演示。

环境准备:阿里云服务器(1 核 2G,1M 带宽),CentOS 7.4 64 位。

由于 Docker-CE 支持 64 位版本的 CentOS 7 ,并且要求内核版本不低于 3.10,首先我们需要卸载掉旧版本的 Docker:

我们执行以下安装命令去安装依赖包:

安装docker

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

当然在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装:

具体可以参看 docker-install 的脚本:

执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker CE 的 Edge 版本安装在系统中。安装完成后,运行下面的命令,验证是否安装成功:

Docker 需要用户具有 sudo 权限,为了避免每次命令都输入sudo,可以把用户加入 Docker 用户组(官方文档)。

启动 Docker-CE:

Docker 是服务器—-客户端架构。命令行运行docker命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动(官方文档)。

管理镜像:

image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作。为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库 Docker Hub 是最重要、最常用的 image 仓库。此外,出售自己制作的 image 文件也是可以的。

2.2 Docker 的简单运用 Hello World

下面,我们通过最简单的 image 文件”hello world”,感受一下 Docker。需要说明的是,国内连接 Docker 的官方仓库很慢,还会断线,需要将默认仓库改成国内的镜像网站,具体的修改方法在下一篇文章的第一节。有需要的朋友,可以先看一下。首先,运行下面的命令,将 image 文件从仓库抓取到本地。

上面代码中,docker image pull是抓取 image 文件的命令。library/hello-world是 image 文件在仓库里面的位置,其中library是 image 文件所在的组,hello-world是 image 文件的名字。由于 Docker 官方提供的 image 文件,都放在library组里面,所以它的是默认组,可以省略。因此,上面的命令可以写成下面这样。

抓取成功以后,就可以在本机看到这个 image 文件了。

现在,运行这个 image 文件。

docker container run命令会从 image 文件,生成一个正在运行的容器实例。

注意,docker container run命令具有自动抓取 image 文件的功能。如果发现本地没有指定的 image 文件,就会从仓库自动抓取。因此,前面的docker image pull命令并不是必需的步骤。

如果运行成功,你会在屏幕上读到下面的输出。

输出这段提示以后,hello world就会停止运行,容器自动终止。对于那些不会自动终止的容器,必须使用docker container kill 命令手动终止。

管理容器文件

image 文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。

上面命令的输出结果之中,包括容器的 ID。很多地方都需要提供这个 ID,比如上一节终止容器运行的docker container kill命令。

终止运行的容器文件,依然会占据硬盘空间,可以使用docker container rm命令删除。

运行上面的命令之后,再使用docker container ls –all命令,就会发现被删除的容器文件已经消失了。

2.3 Dockerfile 文件

学会使用 image 文件以后,接下来的问题就是,如何可以生成自己的镜像呢?如果你要推广自己的软件,势必要自己制作 image 文件。docker提供一种Dockerfile 文件的方式来生成本地镜像。它是一个文本文件,用来配置 image。Docker 根据 该文件生成二进制的镜像文件。

首先,每个指令的前缀必须大写。

FROM 指定基础镜像,后可跟镜像名字或镜像id。

例:FROM centos:6.0

MAINTAINER 作者 指定作者

例:MAINTAINER root

ADD 把文件复制到到容器的指定目录,如果是tar包会自动解压,后可跟本地文件或url,如果是url,功能类似于wget

例:ADD nginx-1.9.3.tar.gz /usr/local

RUN 告诉docker要在镜像内执行的命令,后可跟shell命令或普通命令

例:1.RUN useradd test 2.RUN /bin/echo “hello test”

CMD 容器启动时要运行的命令

例:1.CMD [“nginx”] 2.CMD [“service mysqld start”]

RUN & CMD 区别:
RUN是构建容器时就运行的命令以及提交运行结果,即执行 docker build时运行,一个dockerfile可以有多个;
CMD是容器启动时执行的命令,即执行 docker run时运行,一个dockerfile只有1个
LABEL为镜像指定标签。

例:LABEL version=”1.0″

EXPOSE 将容器的监听端口暴露给外部,这样才能使主机和container建立映射,即在dokcer run使指定-p端口映射关系。

例:EXPOSE 80

ENV 设置环境变量

例:ENV PATH /usr/local/nginx/sbin:$PATH

VOLUME 可实现挂载功能,可以将内地文件夹或者其他容器中的文件夹挂在到这个容器中,容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。所以当数据需要持久化时用这个命令。

例:VOLUME /usr/local/nginx/conf/nginx.conf /etc/nginx/nginx.conf

将主机上的/usr/local/nginx/conf/nginx.conf文件挂在到容器的/etc/nginx/nginx.conf文件
copyadd类似,区别为copy后只能跟本地目录。
workdir 设置工作目录,类似于linux的cd命令。
user 设置启动容器的用户 1.USER daemon 2.USER UID
stopsignal 当容器退出时给系统发送什么样的指令

dockerfile命令其实有好多和linux系统本身命令的功能相似,还是相对比较好理解,为方便理解,我做了一个关于将nginx服务打包成镜像并使用的一个例子。

首先我们需要把我们的要用到的nginx安装包和dockerfile放在同一目录下。

创建Dockerfile文件,其实就是把nginx的安装过程写成了脚本,只不过要符合dockerfile的规范。

构建镜像操作

执行

-t ———指定镜像名和标签
请注意,最后面有一个点 ‘.’,指定dockerfile的路径,也可以写为绝对路径。

执行成功会出现

查看本地镜像可以看到我们构建的镜像

运行我们构建的镜像,映射到本地的80端口:

查看本地端口80

访问本地80端口,成功!

参考文章:
https://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注