Docker 安装
初识 Docker
- 轻量,简单的建模方式.
- 为云计算而生.
- 多平台可以移植,易于构建,易于协作.
- 基础设施即代码:通过 Docker 的镜像,我们可以将创建过程变为自动和且可重复,而且可以做版本管理.
- 不可变基础设施:对无状态服务升级,部署会更为容易和简单,我们无需再修改配置,只需要销毁重建即可.
- 配上 SOA 或 微服务架构,Docker 会更香.
Docker 的结构
解释一下上图的几个关键词:
-
Client
:这就是你所看到的 docker 控制终端. -
DOCKER_HOST
:这是 docker 运行的整体运行时上下文 -
Docker daemon
:这是 Docker 的守护程序,由他来和 Client 进行通信,获取 Client 的命令,并对 Image Container 等组件进行统一管理. -
Images
:这是一切容器运行的模板或者是基础,容器都是通过 image 来创建的. -
Containers
:由 Image 所创建的运行实例,程序都运行在容器中,一个 Image 可以扩展出 N 个 Container -
Docker Registry
: Docker Image 的存放库,一般情况下都是使用官方的 DockerHub.com.不过,你也可以搭建自己的 Docker Registry 将 Image 管理私有化.
Docker Container
Docker 安装成功后,请你在命令行中使用docker info
来确认 Docker 是否正确的安装在本地环境中.
启动你的第一个 Container
docker run -t -i ubuntu /bin/bash
如果,启动成功的话,你会看到你的命令行变成
root@c8fabbcb9f8a:/#
@
符号后面的这串字符可能和我的不太一样,他们都是随机生成的容器 ID
你可以尝试在 Container 终端中使用 ps aux
,hostname
,ip a
等命令,来体会容器的便利性.
你还可以在 Container 中安装你所需要的工具,你可以使用 apt-get update && apt-get install vim
来给他安装 vim.
请你记住,只要不是在 Image 中所包含的,当 Container 被 Remove 后,这一切都将不复存在.
接着,我们来一个个解释命令是什么意思:
-
docker run
:让 docker 启动一个容器的命令. -
-t
:创建一个虚拟的 TTY 终端. -
-i
:代表我们创建的 Container 是会被捕获STDIN
的. -
ubuntu
:这是我们启动 Container 所对应的 Image,如果需要指定版本的话可以通过ubuntu:18.04
这种方式. -
/bin/bash
:这是当 Container 启动完成后,就会执行这个命令.
最后,输入exit
接上回车来停止这个终端.这时候你会退回到你自己的操作系统终端中,那我们怎么去看刚刚创建的容器去哪里了呢.
输入docker ps -a
你会看到下面这样的内容
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c8fabbcb9f8a ubuntu "/bin/bash" 7 seconds ago Exited (0) 4 seconds ago elated_banzai
我们可以通过这些发现很多有用的信息:
-
CONTAINER ID
:我们之前 tty 里面看到的容器 ID. -
IMAGE
: Container 所使用的容器. -
COMMAND
: Container 启动后所使用的命令. -
CREATED
: Container 创建的时间. -
STATUS
: Container 目前的状态. -
PORTS
: Container 所暴露出内部的端口,不过我们这个实例没有,后面的实例中我们会看到的具体的操作和概念. -
NAMES
:Container 的名字,我们可以在 container run 的时候通过--name
指定名字,如果没有指定,那么 docker 会自动生成一个名字.
查看 Container
docker ps
,docker container ls
这 2 个命令有同样的结果,就是查看当前正在运行的 Containers.如果,需要查看所有的容器,需要在命令后面加上-a
重启已经停止的 Container
docker start elated_banzai
或者docker start c8fabbcb9f8a
在 docker start
命令后面跟上 container 的 name 或者 id 都可以重新启动它.
但是,我们会发现这次启动以后,我们没有进入终端,但是查看最新的状态,他却是 UP 的状态.这是为什么呢
因为,我们这次只是重启了 Container,但是并没有通过 tty
连接到这个容器上去.
那我们还想连接回去怎么办呢,下面我们会讲到
通过 tty 连接运行中的 Container
docker exec -i -t elated_banzai /bin/bash
当然,上面使用 Container name
的地方也可以互换为 Container id
.在 docker 命令中,所有指定 Container 的地方,都是 name
和 id
可以互换的.
这个命令比较简单,与 docker run
基本上是类似的,这里就不做展开讲解了.
Container 输出的查看
首先,我们下面的命令,来创建一个叫 log_container
的 Container
docker run -d --name log_container ubuntu /bin/sh -c "while true;do echo hello world; sleep 3; done"
这时,可能你会发现,这条命令里面多了一个 -d
的配置,他是用来指定使用 daemon 的模式来运行这个 Container.
我们在最后写了一个死循环的 shell 脚本,让他每 3 秒输出一个 hello world.
回车以后,他只是输出了这个 container 的 id
,我们可以通过下面的命令结合 id
或者 name
来看输出的内容.
docker logs log_container
添加-f
来持续查看他的输出,这个和 linux 中的 tail
命令是类似的.
我们还可以添加-t
来查看输出的时间戳.
查看 Container 内部的进程
docker top name/id
查看所有 Containers 或者指定的 Container 的统计信息
docker stats
,docker stats ContainerName1 ContainerName2...
停止 Container
docker stop name/id
删除 Container
docker rm name/id
这个命令如果不添加-f
,那我们只能删除已经停止的容器.
深入查看 Container 信息
docker inspect name/id
这个命令显示的内容比较多,不过大部分都能通过keyname
看懂,如果有不清楚的部分请自行查阅相关文档.
Image
查看 Images
docker images
,docker image ls
删除 Image
docker images
Dockerfile
Dockerfile
是一个使用基本的 Docker DSL 语法的指令来构建 Docker Image 的文件.
通过,Dockerfile
来构建 Image ,更具备重复性,透明性和幂等性.
基础理论基本上介绍的差不多了,那么我们直接上干货.
用 Docker 搭建一个 redis cluster
创建 replica Base Image
首先,我们创建 Redis 的主镜像
$ mkdir redis-replica
$ cd redis-replica
$ touch Dockerfile
Dockerfile:
#使用的母镜像
FROM redis
#维护者信息,这里填的是我自己的邮箱
MAINTAINER crowhyc@163.com
#环境变量,添加以后可以在容器和接下来的命令里面都可以使用
#这个环境变量是用于定义这个镜像的版本和日期
ENV REFESHED_AT 2020-04-01
#用来向基于Image创建的 Container 添加卷
#一个卷是可以存在于一个或多个 Container 内特定的目录,这个目录可以共享数据或对数据进行持久化功能
#下面这个 VOLUME 会在 Container 里面创建这 2 个目录
VOLUME ["/var/lib/redis","/var/log/redis/"]
#基于此 Image 创建的 Container 会对外暴露 6379 接口
#可以通过 docker ports name/id 来查询 Container 暴露接口与本地接口所映射的关系
#也可以在 Container docker run 的时候通过-p 6379:6379 把他绑定到指定的 port 上
EXPOSE 6379
#用于指定一个 Container 启动时要运行的命令,类似于后面会遇到的 RUN 命令
#只是 RUN 指令是指定 Image 被构建时需要运行的命令
#docker run 命令可以覆盖 CMD 命令,这里留空的目的是让 docker run 的时候可以自定义需要执行的命令
#后面介绍到的 ENTRYPOINT 命令则不可以被覆盖
CMD []
保存文件后,我们运行下面的这条命令
docker build -t crowhyc/redis-replica:1.0 .
我们来解释一下这条命令
docker build
是用来创建镜像的.
-t
和crowhyc/redis-replica:1.0
是用来表明后面我们会用这种格式的方式来指定 Image 的名称和版本.
最后,还有一个不起眼的.
这个是用来指定 Dockerfile 的地址..
是说明 Dockerfile 就在当前目录下
我们不会 run 这个 Image.它是接下来我们 redis-primary 和 redis-slave 的母镜像
创建 redis primary Image
$ mkdir redis-primary
$ cd redis-primary
$ touch Dockerfile
FROM crowhyc/redis-primary:1.0
MAINTAINER crowhyc "crowhyc@163.com"
ENV REFRESHED_AT 2020-04-01
#是 Container 启动以后执行的命令,与 CMD 不同,Container 启动的命令不能覆盖它
ENTRYPOINT ["redis-server","--logfile /var/log/redis/redis-server.log"]
紧接着,我们创建 redis 的主镜像
docker build -t crowhyc/redis-primary:1.0 .
创建 redis slave Image
$ mkdir redis-slave
$ cd redis-slave
$ touch Dockerfile
FROM crowhyc/redis-replica:1.0
MAINTAINER crowhyc "crowhyc@163.com"
ENV REFRESHED_AT 2020-04-01
#这里有一点需要注意的是,我们第三个参数使用的是 redis-primary 当我们启动 primary Container 的时候需要与这个名字相同
ENTRYPOINT ["redis-server","--logfile /var/log/redis/redis-server.log","--slaveof redis-primary 6379"]
启动 redis cluster 并查看状态
创建 Network
docker network create redis-cluster
首先,我们使用上面的命令创建一个新的 network.
docker network
是 docker Container 之间用来通信的网络,用户可以自己创建网络,用来组件自己的集群网络.
docker network ls
同样,我们也可以用上面的命令来查看所有的网络
启动 redis-primary
接着,我们使用下面的docker run
来启动我们的 primary redis server.
docker run -d -h redis-primary --net redis-cluster --name reids-primary crowhyc/redis-primary:1.0
-h
是一个之前没有出现过的新标志,他用来设置 Container 的 hostname,这会覆盖默认的行为即将 Container 主机名设置为 ContainerId.
使用这个标志可以保证redis-primary
被作为 Container 的 hostname,并被本地的 DNS 服务正确解析.
--net
是用来设定这个 Container 所使用的 Network
查看 redis-primary 日志
我们输入 docker logs 命令去查看日志
docker logs -f redis-primary
稍作等待,你会发现--根本什么都没有...那这是为什么呢?
这是因为我们在做 redis-primary
的时候,让日志记录到了/var/log/redis/redis-server.log 这个文件里面.
接着,我们用更加巧妙的方式去观察类似这种情况下的日志输出.
docker run -it --rm --volumes-from redis-primary ubuntu cat /var/log/redis/redis-server.log
这下我们就能看到对应的 redis-primary
的日志了,如果出现了Ready to accept connections
说明 redis-primary
已经启动成功.
接着我们来为他启动 2 个 redis-slave
吧
启动多个 redis-slave
docker run -d -h redis-slave01 --net redis-cluster crowhyc/redis-slave:1.0
docker run -d -h redis-slave02 --net redis-cluster crowhyc/redis-slave:1.0
接着我们用上面刚刚学的 docker run 来观察 slave 是否和 primary 建立了联系
docker run -it --rm --volumes-from redis-slave01 ubuntu cat /var/log/redis/redis-server.log
docker run -it --rm --volumes-from redis-slave02 ubuntu cat /var/log/redis/redis-server.log
如果,我们能看到类似于MASTER <-> REPLICA sync: Finished with success
这样的日志,说明我们 slave 与 primary 已经连接成功了
接下来,我们用 docker 的方式来测试 redis 吧
简要 redis 集群测试
docker run -it --rm --net redis-cluster redis /bin/bash
紧接着我们连接到 redis-primary
redis-cli -h redis-primary
然后,我们 SET 一个值
redis-primary:6379> set "test" 1234
接着,我们再进入 redis-slave01
docker exec -it redis-slave01 /bin/bash
redis-cli -h localhost
get "test"
如果,我们在执行完get
命令后看到了"1234"说明我们的 redis 集群已经完成搭建了.