docker 基础知识
记录 docker 基础知识,个人认为学习 docker 相关主要在于实战,基础知识了解之后进行实战来体会要更好些
参考文章:
- docker教程 - 菜鸟教程 ,想看基础知识来看菜鸟是很方便的
docker 是啥子
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版),我们用社区版就可以了。
docker 架构
Docker 包括三个基本概念:
- 镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
- 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
- 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。
Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。Docker 容器通过 Docker 镜像来创建,容器与镜像的关系类似于面向对象编程中的对象与类,一个镜像可以实例化出多个容器运行。 docker镜像和容器的关系可以参考 这个文章 讲的,比较通俗易懂,一时搞不懂也无妨,在使用过镜像和容器之后兴许会有新的体悟。
概念 | 说明 |
---|---|
Docker 镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。 |
Docker 容器(Container) | 容器是独立运行的一个或一组应用,是镜像运行时的实体。 |
Docker 客户端(Client) | Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。 |
Docker 主机(Host) | 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。 |
Docker Registry | Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。 一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。 通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。 |
Docker Machine | Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。 |
docker 安装
安装方式网上能找到太多了,我这里只列举我用的,不满足的话再去网上寻找你需要的即可
CentOS 7.5 64位
# 以脚本的方式安装
curl -sSL https://get.daocloud.io/docker | sh
# 查看版本
docker version
# 启动 docker
systemctl start docker
# 停止 docker
systemctl stop docker
# 重启 docker
systemctl restart docker
MacOS
略
Windows
略略
docker 镜像加速
设置阿里云镜像加速器,登陆后,左侧菜单选中镜像加速器就可以看到你的专属地址了,开了加速之后速度嗷嗷快。
docker 使用
Hello World
典中典之 Hello World。
Docker 允许你在容器内运行应用程序, 使用 docker run 命令来运行一个容器 并在容器内运行一个应用程序。
# Docker 以 ubuntu15.10 镜像创建一个新容器,然后在容器里执行 bin/echo "Hello world",然后输出结果。
docker run ubuntu:15.10 /bin/echo "Hello world"
各参数解析:
- docker: docker 的二进制执行文件
- run:与前面的 docker 组合来运行一个容器
- ubuntu:15.10:指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
- /bin/echo "Hello world":启动容器后,在容器内执行的命令
运行交互式的容器
我们通过 docker 的两个参数 -i -t,让 docker 运行的容器实现"对话"的能力
docker run -i -t ubuntu:15.10 /bin/bash
- -i 允许你对容器内的标准输入 (STDIN) 进行交互
- -t 在新容器内指定一个伪终端或终端
输完命令回车之后你会发现当前命令行的前缀变了,这时我们已经是在容器内部了,可以尝试运行命令 cat /proc/version和ls分别查看当前系统的版本信息和当前目录下的文件列表
可以通过运行 exit 命令或者使用 CTRL+D 来退出容器。
以后台模式启动容器
docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
# 输出: 2b1b7a428627c51ab8810d541d759f072b4fc75487eed05812646b8534a2fe63
在输出中,我们没有看到期望的 "hello world",而是一串长字符,这个长字符串叫做容器 ID,对每个容器来说都是唯一的,我们可以通过容器 ID 来查看对应的容器发生了什么。通过 docker ps
可以查看当前正在运行的容器(docker ps -a
查看所有容器)
列名 | 备注 |
---|---|
CONTAINER | 容器 ID |
IMAGE | 使用的镜像 |
COMMAND | 启动容器时运行的命令 |
CREATED | 容器的创建时间 |
STATUS | 容器状态:created(已创建);restarting(重启中);running 或 Up(运行中);removing(迁移中);paused(暂停);exited(停止);dead(死亡) |
PORTS | 容器的端口信息和使用的连接类型(tcp\udp) |
NAMES | 自动分配的容器名称 |
# 查看日志
docker logs 容器名或容器ID
# 停止容器
docker stop 容器名或容器ID
进入容器
# 如果退出,容器也会停止
docker attach 容器ID
# 使用 exec 即使退出也不会停止容器
docker exec -it 243c32535da7 /bin/bash
导出和导入容器
# 导出容器 1e560fca3906 快照到本地文件 ubuntu.tar
docker export 1e560fca3906 > ubuntu.tar
# 可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1
cat docker/ubuntu.tar | docker import - test/ubuntu:v1
# 此外,也可以通过指定 URL 或者某个目录来导入,例如:
docker import http://example.com/exampleimage.tgz example/imagerepo
删除容器
删除容器时,容器必须是停止状态,否则会报错
# 删除指定容器
docker rm -f 1e560fca3906
# 清理所有处于终止状态的容器
docker container prune
常用命令&参数
# -p 端口映射,将容器的 4321 端口映射到主机的 1234 端口
# -d 后台运行
docker run -p 1234:4321 -d centos
# 当我们创建一个容器的时候,docker 会自动对它进行命名。我们可以使用 --name 标识来命名容器
docker run --name test1 centos
# 查看指定容器的端口信息 或者通过 docker ps 查看所有容器的端口情况
docker port 容器ID或者容器名
# 像使用 tail -f 一样来输出容器内部的标准输出
docker logs -f 容器ID或者容器名
# 查看容器内部运行的进程
docker top 容器ID或者容器名
# 停止容器
docker stop 容器ID或者容器名
# 重启容器
docker restart 容器ID或者容器名
# 查看最后一次创建的容器
docker ps -l
docker 镜像
当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载
查看
使用 docker images
查看本机已拉取的镜像,各列信息如下
列名 | 说明 |
---|---|
REPOSITORY | 表示镜像的仓库源 |
TAG | 镜像的标签 |
IMAGE ID | 镜像ID |
CREATED | 镜像创建时间 |
SIZE | 镜像大小 |
获取
使用 docker pull 镜像名:版本
如果不加版本默认拉取 latest
查找
使用 docker search 名字
查询可用的镜像
列名 | 说明 |
---|---|
NAME | 镜像仓库源的名称 |
DESCRIPTION | 镜像的描述 |
OFFICIAL | 是否 docker 官方发布 |
STARS | 类似 Github 里面的 star,表示点赞、喜欢的意思 |
AUTOMATED | 自动构建 |
删除
使用 docker rmi 镜像名或镜像ID
删除一个已拉取过的镜像
创建
一般通过以下两种方式对镜像进行更改
- 从已经创建的容器中更新镜像,并且提交这个镜像
以镜像创建容器后进入容器中修改自己想要更改的内容,执行 exit 退出容器,然后 执行 docker commit -m="提交的描述信息" -a="指定的镜像作者" 容器ID 镜像名字(推荐 作者/名字:版本 的命名方式)
来以这个容器创建一个新的镜像
- 使用 Dockerfile 指令来创建一个新的镜像
通过创建一个 Dockerfile 文件,并在文件中写入构建指令来从零开始构建一个镜像,执行命令 docker build -t runoob/centos:6.7 .
, -t
指定镜像名字(推荐 作者/名字:版本 的命名方式), .
指定 Dockerfile 文件所在目录,可以指定 Dockerfile 的绝对路径,下文会提到 Dockerfile 文件怎么写,在这里知道有这么个方式就好了。
打标签
通过 docker tag 镜像ID 作者/镜像:版本
为镜像创建一个新的标签,打标签的时候最好保持和原镜像的 作者/镜像
相同,因为打完标签后相当于是同一镜像的不同版本,他们的 镜像ID 是相同的。
容器连接
端口映射
-P
:容器内部端口随机映射到主机的高端口-p
:容器内部端口随机映射到主机的指定端口,-p 1234:4231
,要注意指的是容器的4321
端口映射到主机的1234
端口
默认绑定 tcp 端口,如果需要绑定 udp 端口,在端口后加 /udp
即可
通过 -p 127.0.0.1:1234:4321
指定容器绑定的网络地址,这样可以通过主机的 127.0.0.1:1234 访问容器的 4321 端口
使用 docker port 镜像名字 端口
可以方便的查看容器的端口绑定情况
容器互联
docker 有一个连接系统允许将多个容器连接在一起,共享连接信息,docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。使用 docker network create -d bridge test-net
来创建一个容器网络,-d 指定网络类型,有 bridge、overlay ,其中 overlay 网络类型用于 Swarm mode 暂时不管,test-net 是网络的名称。
在执行 docker run 命令的时候使用 --network test-net 来指定要连接到的网络。例如:
docker run -itd --name test1 --network test-net ubuntu /bin/bash
docker run -itd --name test2 --network test-net ubuntu /bin/bash
这样运行后在 test1 和 test2 中互 ping 是可以通的,当然前提是已经安装了 ping 。
配置 DNS
我们可以在宿主机的 /etc/docker/daemon.json 文件中增加以下内容来设置全部容器的 DNS:
{
"dns" : [
"114.114.114.114",
"8.8.8.8"
]
}
设置后,启动容器的 DNS 会自动配置为 114.114.114.114 和 8.8.8.8 ,配置完,需要重启 docker 才能生效,查看容器的 DNS 是否生效可以使用命令 docker run -it --rm ubuntu cat etc/resolv.conf
,它会输出容器的 DNS 信息。
如果只想在指定的容器设置 DNS,则可以使用命令 docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu
。参数说明:
参数 | 说明 |
---|---|
--rm | 容器退出时自动清理容器内部的文件系统 |
-h HOSTNAME 或者 --hostname=HOSTNAME | 设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts |
--dns=IP_ADDRESS | 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名 |
--dns-search=DOMAIN | 设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com |
如果在容器启动时没有指定 --dns 和 --dns-search,Docker 会默认用宿主主机上的 /etc/resolv.conf 来配置容器的 DNS
仓库管理
仓库(Repository)是集中存放镜像的地方。以下介绍一下 Docker Hub。当然不止 docker hub,只是远程的服务商不一样,操作都是一样。Docker Hub 是目前 Docker 官方维护的一个公共仓库,我们的大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。在 https://hub.docker.com 免费注册一个 Docker 账号。我们使用 Docker Hub 上的公开镜像是不需要登录的,像上文从 Docker Hub 拉取镜像时也未曾要求我们登录,注册登录是便于管理我们自己的镜像仓库。
登入登出
docker login # 登入,如果本地未登录过会要求输入用户名和密码,如果登陆过且未执行登出操作就会是以下的输出
# Authenticating with existing credentials...
# Login Succeeded
docker logout # 登出
# Removing login credentials for https://index.docker.io/v1/
How to know if docker is already logged in to a docker registry server
docker login actually isn't creating any sort of persistent session, it is only storing the user's credentials on disk so that when authentication is required it can read them to login
需要注意的是,docker login 并没有创建一个持久的对话,它只是将你的信息存储在硬盘上,以便需要的时候读取进行验证,如果你之前登录过的话,那么再次登录就会提示 Authenticating with existing credentials
。然后在登出的时候看输出也可以知道,此时你的身份信息已经移除了
推送镜像
用户登录后就可以推送自己的镜像到 Docker Hub ,命令示例:
docker tag ubuntu:18.04 username/ubuntu:18.04 # 打标签
docker image ls # 查看本地有无
docker push username/ubuntu:18.04 # 推送到 Docker Hub
docker search username/ubuntu # 查看 Docker Hub 上能搜到了不