Docker快速入门

·  阅读 266
Docker快速入门

2013年Docker发布至今,被认为可能会改变软件行业,到现在,它确实在一定程度上改变了软件行业。

这篇文章主要介绍docker的基本使用,提供常用命令的快速查询。目的在于能让普通开发者在短时间内能对docker有一个直观的感受,进而使用docker快速搭建开发环境。

环境配置难

相信不少小伙伴都有过这样的体验。

  • 想要学习linux,那么我们需要去安装linux系统或者安装linux虚拟机;
  • 如果你是后端开发者,你可能要搭建php或java的开发环境(redis、mysql等),然后进行繁琐的环境变量等配置;
  • 安装一个软件,然后发现这个软件又依赖一些其他的软件,需要逐个去安装;
  • 跟着一个教程学习,发现按相同的方法自己的代码run不起来;

这些环境问题docker都可以解决,它可以提供一致的运行环境。

什么是Docker

Docker 最初是 dotCloud 公司创始人 Solomon Hykes (opens new window)在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源 (opens new window),主要项目代码在 GitHub (opens new window)上进行维护。

Docker 自开源后受到广泛的关注和讨论,至今其 GitHub 项目 (opens new window)已经超过 5 万 7 千个星标和一万多个 fork。甚至由于 Docker 项目的火爆,在 2013 年底,dotCloud 公司决定改名为 Docker (opens new window)

Docker 使用 Google 公司推出的 Go 语言 (opens new window)进行开发实现,基于 Linux 内核的 cgroup (opens new window)namespace (opens new window),以及 OverlayFS (opens new window)类的 Union FS (opens new window)等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术 (opens new window)。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。

与传统的虚拟机相比,docker有以下优点:

特性容器虚拟机
启动秒级分钟级
硬盘使用一般为 MB一般为 GB
性能接近原生弱于
系统支持量单机支持上千个容器一般几十个

Docker的用途

Docker 的主要用途,目前有以下几类。

(1)提供一致的运行环境。 保证开发环境、测试环境、预发环境、生产环境的一致性,避免特定环境出现的bug。

(2)提供弹性的云服务。 因为Docker能提供一致的运行环境,我们可以很轻松的实现服务的迁移。另外,Docker的启动和销毁都很快,可以做到秒级、甚至毫秒级的启动时间,能实现快速的扩容和缩容。

(3)持续交付和部署。 对开发和运维(DevOps (opens new window))人员来说,使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) (opens new window)系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) (opens new window)系统进行自动部署。

(4)组建微服务架构。 在单台服务器上,或者我们自己的笔记本电脑上,可以运行多个服务,包括服务依赖的后端资源,比如redis、mysql、kafka等,甚至我们还可以把这些后端资源按集群的方式部署。借助Docker我们可以在一台机器上模拟微服务架构。

安装Docker

Docker 的安装参考官方文档。

Docker还提供了桌面版本。

docker-tutorial-mac.png

镜像(Image)

Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像 不包含 任何动态数据,其内容在构建之后也不会被改变。

Docker镜像是分层存储的,镜像构建时,会一层层构建,前一层是后一层的基础。不同的镜像可以复用"层",节省存储空间。

开发者可以自己制作镜像,也可以使用别人制作好的镜像。一般来说,比较常用的镜像在官方仓库Docker Hub上都可以找到。

从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:

$ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
复制代码
  • Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub(docker.io)。
  • 仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。
➜  ~ docker pull ubuntu:20.04
20.04: Pulling from library/ubuntu
a31c7b29f4ad: Pull complete
Digest: sha256:b3e2e47d016c08b3396b5ebe06ab0b711c34e7f37b98c9d37abe794b71cea0a2
Status: Downloaded newer image for ubuntu:20.04
docker.io/library/ubuntu:20.04
复制代码

上面的命令是从官方仓库拉取Ubuntu的20.04版本的镜像。最后一行就是镜像的完整的名字。

使用同样的方式,我们再安装一下redis和mysql-server的镜像。

➜  ~ docker pull redis:latest
latest: Pulling from library/redis
33847f680f63: Pull complete
26a746039521: Pull complete
18d87da94363: Pull complete
5e118a708802: Pull complete
ecf0dbe7c357: Pull complete
46f280ba52da: Pull complete
Digest: sha256:cd0c68c5479f2db4b9e2c5fbfdb7a8acb77625322dd5b474578515422d3ddb59
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest

➜  ~ docker pull mysql/mysql-server:5.7
5.7: Pulling from mysql/mysql-server
b5be27e1996f: Pull complete
091844bfb0ec: Pull complete
3cb5fb55841d: Pull complete
47644b99acea: Pull complete
3bd4cb0b78d1: Pull complete
a62c52d3a764: Pull complete
20396840d0b1: Pull complete
38b3da6a86f7: Pull complete
Digest: sha256:779c5ba746fe052579c50a0533eaf38ee1ab75d348534d5db092028242a32eed
Status: Downloaded newer image for mysql/mysql-server:5.7
docker.io/mysql/mysql-server:5.7
复制代码

实测,官方镜像的拉取速度还是可以的,如果你从官方下载镜像很慢,可以使用 镜像加速器

在桌面版Docker也可以看到我们刚才拉取的镜像。

docker-image.png

如果你不喜欢命令行的操作,也完全可以在桌面版完成镜像的管理,容器的启动等操作。

镜像的操作

列出镜像

➜  ~ docker image ls
REPOSITORY           TAG       IMAGE ID       CREATED        SIZE
redis                latest    aa4d65e670d6   39 hours ago   105MB
mysql/mysql-server   5.7       8b7280d401c0   4 days ago     385MB
ubuntu               20.04     c29284518f49   11 days ago    72.8MB
复制代码

列表包含了 仓库名标签镜像 ID创建时间 以及 所占用的空间

查看镜像所占空间

➜  ~ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          3         0         563MB     563MB (100%)
Containers      0         0         0B        0B
Local Volumes   0         0         0B        0B
Build Cache     0         0         0B        0B
复制代码

通过 docker system df 命令来便捷的查看镜像、容器、数据卷所占用的空间。因为这里我们还没有启动镜像,所以其他数据都是0。

删除镜像

如果要删除本地的镜像,可以使用 docker image rm 命令,其格式为:

$ docker image rm [选项] <镜像1> [<镜像2> ...]
复制代码

其中,<镜像> 可以是 镜像短 ID镜像长 ID镜像名 或者 镜像摘要

比如我们可以使用命令dokcer image rm redisdocker image rm aa4 来删除redis镜像。

➜  ~ docker image rm redis
Untagged: redis:latest
Untagged: redis@sha256:cd0c68c5479f2db4b9e2c5fbfdb7a8acb77625322dd5b474578515422d3ddb59
Deleted: sha256:aa4d65e670d6518e5da96ca9d1a76370a942970a8802e6d5cc6bcf058ab12ca7
Deleted: sha256:3bd00d38f5ca70200050477c527cc60cfdf82911d6fe03932e2bcae31a95cfa2
Deleted: sha256:22722fde392d188cfbe5bbd0c2451cc71cf5b000afc0e5114c1066bb5e113ec9
Deleted: sha256:38212b55ef525e86cd726cd83c1a82a6009c68d24771d6e93d439fdc88e66f0e
Deleted: sha256:188c498579cef37b65a93d6448c6b129fa07d5740fc213a18843ff22d80cd10d
Deleted: sha256:2117165cd53c98f13ec7af36c9d8acd239fc541c847efaccb49885decf615d68
Deleted: sha256:814bff7343242acfd20a2c841e041dd57c50f0cf844d4abd2329f78b992197f4
复制代码

删完了redis镜像,后面还是需要的,ok,那我们再装回来。

定制镜像

Dockerfile 是一个文本文件,其内包含了一条条的 指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

接下来,我们以linux命令行下两个小游戏为例构建一个镜像。

step 1

在本地新建一个sound.txt的文件,里面随便写几句话。

step 2

新建一个名字为Dockerfile的文件,里面写入以下命令:

FROM ubuntu:20.04
COPY ./sound.txt /
WORKDIR /
RUN apt-get update && apt-get -y install sl && apt-get -y install cowsay &&  echo "export PATH=/usr/games:$PATH" > /etc/bash.bashrc
复制代码

FROM 就是指定 基础镜像,我们构建的镜像是以ubuntu:20.04为基础的。

COPY是把当前目录(这个当前目录指的是使用构建命令时指定的目录)下的sound.txt复制到构建的镜像的根目录下。

WORKDIR /:指定接下来的工作路径为/

接下来的RUN命令时执行linux的bash命令,安装 slcowsay两个软件,因为默认是安装在了/usr/games目录下,所以我们把/usr/games添加到PATH中。

step 3

执行docker build命令构建镜像。

➜  Documents docker build -t ubuntu-game:0.1 .
[+] Building 0.3s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                       0.2s
 => => transferring dockerfile: 37B                                        0.2s
 => [internal] load .dockerignore                                          0.1s
 => => transferring context: 2B                                            0.1s
 => [internal] load metadata for docker.io/library/ubuntu:20.04            0.0s
 => [internal] load build context                                          0.0s
 => => transferring context: 30B                                           0.0s
 => [1/4] FROM docker.io/library/ubuntu:20.04                              0.0s
 => CACHED [2/4] COPY ./sound.txt /                                        0.0s
 => CACHED [3/4] RUN apt-get update && apt-get -y install sl && apt-get -  0.0s
 => exporting to image                                                     0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:9535c4b11c3ffdd60225167968f9af8e5a69cf1d5df85  0.0s
 => => naming to docker.io/library/ubuntu-game:0.1
复制代码

docker build命令后面跟的点,是用来指定当前目录为构建上下文的路径。

build命令运行成功后,使用docker image ls命令就能看到我们构建的ubuntu-game镜像。

step 4

看下效果。

docker run --name game -it ubuntu-game:0.1
复制代码

使用上面的命令启动镜像,会进入ubuntu-game的终端,命令的解释会在下一节讲解容器的时候详细解释。

根目录下有我们创建的sound.txt文件。

root@fe5f88e5a625:/# ls -l sound.txt
-rw-r--r-- 1 root root 49 Jul 25 05:05 sound.txt
复制代码

执行 source .bashrc使配置的环境变量生效。

执行以下命令,就启动了cowsay游戏,可以看到,一头牛吟出了杜甫的诗句。关于 cowsay的更多玩法见Cowsay

root@16a4b6b15b8c:/# cat sound.txt  | cowsay
 __
/ 风急天高猿啸哀,渚清沙白鸟  \
\ 飞回。  /
 --
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
复制代码
root@98e83032d71c:/# sl
复制代码

执行sl命令,会有一列火车在终端上自左而右,冒着白烟,轰隆隆的驶过。

train.png

容器

简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。

启动容器

例如,下面的命令输出一个 “Hello World”,之后终止容器。

➜  ~ docker run ubuntu:20.04 /bin/echo 'Hello world'
Hello world
复制代码

这跟在本地直接执行 /bin/echo 'hello world' 几乎感觉不出任何区别。

下面的命令则启动一个 bash 终端,允许用户进行交互。

➜  ~ docker run -t -i ubuntu:20.04 /bin/bash
root@1d52bb27322e:/#
复制代码

其中,-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开。

在交互模式下,用户可以通过所创建的终端来输入命令,例如

root@1d52bb27322e:/# ls
bin   dev  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  etc  lib   lib64  media   opt  root  sbin  sys  usr
复制代码

使用docker psdocker container ls 命令可以查看正在运行的容器。

➜  ~ docker ps
CONTAINER ID   IMAGE          COMMAND       CREATED         STATUS         PORTS     NAMES
1d52bb27322e   ubuntu:20.04   "/bin/bash"   2 minutes ago   Up 2 minutes             pensive_bouman
复制代码

使用docker ps -adocker container ls -a 命令则可以查看所有的容器,包括已经停止运行的。

➜  ~ docker ps -a
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS                      PORTS     NAMES
1d52bb27322e   ubuntu:20.04      "/bin/bash"              5 minutes ago    Exited (0) 6 seconds ago              pensive_bouman
24604b36f7e8   ubuntu:20.04      "/bin/echo 'Hello wo…"   5 minutes ago    Exited (0) 5 minutes ago              practical_shtern
98e83032d71c   ubuntu-game:0.1   "bash"                   19 minutes ago   Exited (0) 11 minutes ago             game
复制代码

已经停止运行的容器,可以再次启动吗?答案是可以的。

利用 docker container start 命令,直接将一个已经终止(exited)的容器启动运行。

➜  ~ docker start 24
复制代码

上面启动容器的命令可以省略掉container,24表示要启动容器的id的短摘要,使用容器的长摘要或容器名字也是可以的。

容器后台运行和进入容器

需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d 参数来实现。

比如,我们在后台启动一个mysql的容器。

➜  ~ docker image ls mysql/mysql-server
REPOSITORY           TAG       IMAGE ID       CREATED      SIZE
mysql/mysql-server   5.7       8b7280d401c0   4 days ago   385MB
复制代码

我们前面已经安装过mysql-server的镜像,现在把它启动起来。

➜  ~ docker run --name mysql -d mysql/mysql-server:5.7
9f6e2fd2501306db7ade6b940f11f3c3e7f0495976447541742e1de9481f9c7e
➜  ~ docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED         STATUS                            PORTS                 NAMES
9f6e2fd25013   mysql/mysql-server:5.7   "/entrypoint.sh mysq…"   4 seconds ago   Up 2 seconds (health: starting)   3306/tcp, 33060/tcp   mysql
复制代码

上面的命令是我们启动了mysql-server的容器,并给它起了个别名叫mysql。

我们还可以停止这个容器。

docker stop mysql
复制代码

重启容器。docker container restart 命令会将一个运行态的容器终止,然后再重新启动它。

后台运行的容器,要获取容器的输出信息,可以通过 docker container logs 命令。

要进入一个后台运行的容器,使用exec命令。

docker exec 后边可以跟多个参数,这里主要说明 -i -t 参数。

只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。

-i -t 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。

删除容器

可以使用 docker container rm 来删除一个处于终止状态的容器。例如

➜  ~ docker container rm mysql
mysql
复制代码

如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL 信号给容器。

docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。

➜  ~ docker container prune
复制代码

例子

运行 mysql-server

安装镜像:

docker pull mysql/mysql-server
复制代码

启动容器:

docker run --name=mysql -d -p 3306:3306 mysql/mysql-server:5.7
复制代码

-p 3306:3306指的是把容器的3306端口映射到本地的3306端口,有了端口映射,我们就可以在本地使用mysql客户端访问mysql了。

运行 redis

安装镜像,从官方镜像拉取最新的redis镜像。

docker pull redis
复制代码

启动容器:

docker run --name redis -d -p 6379:6379 redis
复制代码

-p 6379:6379指的是把容器的6379端口映射到本地的6379端口。

运行consul

安装镜像,从官方镜像拉取最新的consul镜像。

docker pull consul
复制代码

启动容器:

docker run --name consul -d -p 8500:8500 -p 8600:8600/udp consul
复制代码

上面的命令把8500和8600端口都映射到本地。

运行kafka

由于kafka依赖Zookeeper,我们使用Docker Compose的方式拉取镜像。

把下面的yml配置保存为名为docker-compose.yml的文件,在文件所在的路径中,执行docker-compose up命令,就能把zookeeper和kafka镜像安装了,并启动相应的容器。

version: '2'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
    ports:
      - 22181:2181
  
  kafka:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    ports:
      - 29092:29092
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
复制代码

镜像的拉取过程如下所示。

➜  docker compose up
[+] Running 15/15
 ⠿ zookeeper Pulled                                                       72.1s
   ⠿ 96965a3a8424 Pull complete                                           12.8s
   ⠿ eb918a808c15 Pull complete                                           58.2s
   ⠿ 5c2fffeabbf7 Pull complete                                           58.5s
   ⠿ b479bf09eedc Pull complete                                           60.2s
   ⠿ 2e31c2ab64ea Pull complete                                           60.3s
   ⠿ e5161e1fdbdc Pull complete                                           60.4s
   ⠿ 5dcd26e8f603 Pull complete                                           66.5s
   ⠿ 27267efe7f14 Pull complete                                           66.7s
 ⠿ kafka Pulled                                                           71.6s
   ⠿ 4d0d850cd4ad Pull complete                                           13.1s
   ⠿ 7a73120408f4 Pull complete                                           57.5s
   ⠿ 68bcf2239ce4 Pull complete                                           60.1s
   ⠿ e0f07497560d Pull complete                                           65.8s
   ⠿ b88780ca570c Pull complete                                           66.2s
[+] Running 3/3
 ⠿ Network documents_default        Created                                1.0s
 ⠿ Container documents_zookeeper_1  S...                                   2.6s
 ⠿ Container documents_kafka_1      Start...                               3.8s
复制代码

总结

  • Docker能帮助我们快速搭建一致性的环境;
  • Docker可实现弹性扩容,非常适合微服务架构;
  • 介绍了镜像和容器的概念以及相关的操作;
  • 列举了使用容器快速搭建mysql、redis等后端资源的例子。
分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改