什么是docker
解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术,docker三要素:
- 镜像文件-
- 容器虚拟化技术-
- dockerhub-存放docker镜像的仓库,dockerhub是最大的公开仓库,一般国内都是用阿里云的公开仓库
Docker概念
Docker 包括三个基本概念:
镜像
Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统
当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载
docker镜像相关命令
docker image help
# 查看本地所有镜像
docker images
# 拉取指定镜像
docker image pull 【imageName:version】
# 删除选定镜像
docker rmi -f [镜像ID]
# 从 Docker Hub 网站搜索指定镜像
docker search httpd
# 查看镜像/容器/数据卷所占的空间
docker system df
列出本地主机上的镜像
root@iZuf63y0r6z2tc37u0q5l8Z:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
big-screen latest 554298dc4da3 2 days ago 615MB
各个选项说明:
- REPOSITORY: 表示镜像的仓库源
- TAG: 镜像的标签
- IMAGE ID: 镜像ID
- CREATED: 镜像创建时间
- SIZE: 镜像大小
同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如 ubuntu 仓库源里,有 15.10、14.04 等多个不同的版本,我们使用 REPOSITORY:TAG 来定义不同的镜像
设置镜像的标签TAG
root@iZuf63y0r6z2tc37u0q5l8Z:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
big-screen latest 554298dc4da3 2 days ago 615MB
root@iZuf63y0r6z2tc37u0q5l8Z:~# docker tag 554298dc4da3 big-screen:1.0
root@iZuf63y0r6z2tc37u0q5l8Z:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
big-screen 1.0 554298dc4da3 2 days ago 615MB
big-screen latest 554298dc4da3 2 days ago 615MB
创建镜像的几种方式
当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行复制或更改。
- 1、镜像迁移
- 2、从已经创建的容器中更新镜像,并且提交这个镜像(
docker commit
) - 3、使用 Dockerfile 指令来创建一个新的镜像
镜像迁移
将服务器A上的镜像拷贝一份到服务器B上
# 保存一个或多个image到本地tar文件中
docker save 65bb5db22a5b -o 65bb5db22a5b.tar
新的机器加载该镜像
# 加载磁盘上镜像到docker中
docker load -i 65bb5db22a5b.tar
基于某容器创建一个新的镜像
容器打包为镜像(需暂停容器)
docker commit -m="image update" -a="matio" e218edb10161 test/ubuntu:v2
各个参数说明:
- -m: 提交的描述信息
- -a: 指定镜像作者
- e218edb10161: 容器ID
- test/ubuntu:v2: 新的镜像名
镜像打包为本地文件
docker save 65bb5db22a5b -o 65bb5db22a5b.tar
新环境导入该镜像
docker load -i 65bb5db22a5b.tar
然后使用我们的新镜像来启动一个容器
docker run -t -i test/ubuntu:v2 /bin/bash
导入导出容器
将容器导出到本地文件test.tar中
docker export 某容器id > test.tar
导入为新的镜像
docker import test.tar newimage:export
或者
# 导入为镜像
cat ./test.tar | docker import - test/ubuntu:v1
# 通过指定 URL 或者某个目录来导入
docker import http://example.com/exampleimage.tgz example/imagerepo
基于Dockerfile文件构建一个镜像
docker build -t test/centos:6.7 .
参数说明:
- -t :指定要创建的目标镜像名
- . :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径
docker虚悬镜像
root@td1:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web ym 56518dbb1699 4 days ago 174MB
<none> <none> d8edb1a7515c 6 weeks ago 644MB
<none> <none> 10a25c5ea4ec 6 weeks ago 644MB
REPOSITORY和TAG都是none的镜像就是虚悬镜像,建议删除
容器
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等
# 查看当前运行中的容器
docker ps
# 查看所有容器,包括已停止的容器
docker ps -a
# 停止某容器
docker stop [容器ID/Name]
# 启动某容器
docker start [容器ID/Name]
# 重启某容器
docker restart [容器ID/Name]
# 删除选定的容器
docker rm -f [容器ID/Name]
# 查看容器内部运行的进程
docker top [容器ID/Name]
# 查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息
docker inspect [容器ID/Name]
# 查询最后一次创建的容器
docker ps -l
# 从容器复制文件到宿主机
docker cp my_container:/path/in/container /path/on/host
Docker容器连接
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P
或 -p
参数来指定端口映射。
下面我们来实现通过端口连接到一个 docker 容器。
我们创建了一个 python 应用的容器。
runoob@runoob:~$ docker run -d -P training/webapp python app.py
fce072cc88cee71b1cdceb57c2821d054a4a59f67da6b416fceb5593f059fc6d
我们使用 -P 绑定端口号,使用 docker ps 可以看到容器端口 5000 绑定主机端口 32768。
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE COMMAND ... PORTS NAMES
fce072cc88ce training/webapp "python app.py" ... 0.0.0.0:32768->5000/tcp grave_hopper
我们也可以使用 -p 标识来指定容器端口绑定到主机端口。
两种方式的区别是:
- -P: 是容器内部端口随机映射到主机的端口。
- -p: 是容器内部端口绑定到指定的主机端口。
#
docker run -d -p 5000:5000 training/webapp python app.py
# 指定容器绑定的网络地址,比如绑定 127.0.0.1。这样我们就可以通过访问 127.0.0.1:5001 来访问容器的 5000 端口
docker run -d -p 127.0.0.1:5001:5000 training/webapp python app.py
上面的例子中,默认都是绑定 tcp 端口,如果要绑定 UDP 端口,可以在端口后面加上 /udp。
docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
# 查看端口的绑定情况
docker port 容器id
Docker容器互联
端口映射并不是唯一把 docker 连接到另一个容器的方法。
docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。
docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息
先新建一个docker网络
docker network create -d bridge test-net
查看已经建好的docker网络
docker network ls
基于ubuntu镜像后台运行2个容器并连接到刚才新建的test-net网络
docker run -itd --name test1 --network test-net ubuntu /bin/bash
docker run -itd --name test2 --network test-net ubuntu /bin/bash
--name test1
是新的容器名称
进入test1容器
docker exec -it test1 /bin/bash
docker attach也可以进入容器交互,但是使用exit退出后会停止容器,所以工作中很少用
通过 ping 来证明 test1 容器和 test2 容器建立了互联关系。如果容器内没有安装ping,那么可以进入容器后运行以下命令安装ping命令
apt-get update
apt install iputils-ping
运行以下命令测试test1和test2容器的连通性
ping test1
ping test2
这样,test1容器和test2容器建立了互联关系。如果你有多个容器之间需要互相连接,推荐使用 Docker Compose
Docker容器配置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 是否生效可以使用以下命令,它会输出容器的 DNS 信息:
docker run -it --rm 镜像id cat etc/resolv.conf
手动指定容器的DNS
如果只想在指定的容器设置 DNS,则可以使用以下命令:
docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu
如果在容器启动时没有指定 --dns 和 --dns-search,Docker会默认用宿主机上的 /etc/resolv.conf 来配置容器的 DNS
参数说明:
- --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
仓库
仓库可看成一个代码控制中心,用来保存镜像
Docker
官方提供了一个公共仓库服务Docker Hub
用户登录后,可以通过 docker push 命令将自己的镜像推送到 Docker Hub
docker tag ubuntu:18.04 自己的Docker账号/ubuntu:18.04
docker pull太慢解决办法
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://21g5ywxm.mirror.aliyuncs.com",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com",
"http://mirrors.ustc.edu.cn/",
"https://mirrors.tuna.tsinghua.edu.cn/",
"http://mirrors.sohu.com/"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
镜像源 | 地址 |
---|---|
Docker中国区官方 | registry.docker-cn.com |
网易 | hub-mirror.c.163.com |
中科大 | mirrors.ustc.edu.cn/ |
清华大学 | mirrors.tuna.tsinghua.edu.cn/ |
搜狐 | mirrors.sohu.com/ |
docker run
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
--name
指定容器名称,否则docker会随机生成一个容器名称
docker run -d -P --name test training/webapp python app.py
基于镜像training/webapp
创建并后台启动容器test
,然后运行python app.py
命令(-P
是容器内部使用的网络端口随机映射到宿主机端口)
-d
以后台模式运行docker容器,然后输出该容器id
root@iZuf63y0r6z2tc37u0q5l8Z:~# docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
6a8686ce3f9f5e87dd96f7160d1d16b1eec8dc1c04f3555863898190db5bb20c
root@iZuf63y0r6z2tc37u0q5l8Z:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6a8686ce3f9f ubuntu:15.10 "/bin/sh -c 'while t…" 15 seconds ago Up 15 seconds angry_bose
基于镜像ubuntu:15.10
以后台模式运行docker容器,然后输出该容器id。因为没有手动指定容器名称,所以docker为该容器默认指定其名称为angry_bose
-t
在新容器内指定一个伪终端或终端
docker run -t -i ubuntu:15.10 /bin/bash
参数说明:
- -i: 交互式操作。
- -t: 终端。
- ubuntu:15.10: 这是指用 ubuntu 15.10 版本镜像为基础来启动容器。
- /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash
-i
允许你对容器内的标准输入 (STDIN) 进行交互
-p
容器内部端口绑定到指定的主机端口
docker run -d -p 5000:5000 training/webapp python app.py
支持多组配置,比如-p 5000:5000 -p 5001:5002 127.0.0.1:5009:5009
。默认都是绑定tcp端口,也支持绑定udp端口,比如-p 5000:5000/tcp -p 5001:5001/udp
使用 docker port 可以查看指定容器端口和宿主机端口的映射情况。
-P
将容器内部使用的网络端口随机映射到我们使用的主机上
docker run -d -P training/webapp python app.py
使用 docker port 可以查看指定容器端口和宿主机端口的映射情况
--network
连接到指定的docker网络
-v
挂载volumes
- 匿名挂载(匿名卷):在进行数据卷挂载的时候不指定宿主机的数据卷目录,
-v
命令之后直接跟上容器内数据卷所在的路径 - 具名挂载(命名卷):在进行数据卷挂载的时候既指定宿主机数据卷所在路径,又指定容器数据卷所在路径
#匿名挂载(匿名卷)
docker run -d -p 6379:6379 --name mycentos -v /src/volume01
#具名挂载(命名卷) -v 宿主机数据卷所在路径:容器数据卷所在路径
docker run -d -p 6379:6379 --name mycentos -v /home/docker_volume:/src/volume01
命名卷在用过一次之后,以后挂载容器的时候还是可以继续使用,所以一般在需要保存数据的时候使用命名卷的方式。匿名卷则是随着容器的建立而建立,随着容器的关闭而消亡。匿名卷一般用来存储无关痛痒的数据
两种退出方式
Docker hello world
root@iZuf63y0r6z2tc37u0q5l8Z:/# docker run ubuntu:15.10 /bin/echo "Hello world"
Unable to find image 'ubuntu:15.10' locally
15.10: Pulling from library/ubuntu
7dcf5a444392: Pull complete
759aa75f3cee: Pull complete
3fa871dc8a2b: Pull complete
224c42ae46e7: Pull complete
Digest: sha256:02521a2d079595241c6793b2044f02eecf294034f31d6e235ac4b2b54ffc41f3
Status: Downloaded newer image for ubuntu:15.10
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 以 ubuntu15.10 镜像创建一个新容器,然后在容器里执行 bin/echo "Hello world",然后输出结果。
运行交互式的容器
通过 docker 的两个参数 -i -t,让 docker 运行的容器实现 "对话" 的能力
root@iZuf63y0r6z2tc37u0q5l8Z:~# docker run -i -t ubuntu:15.10 /bin/bash
# 此时我们已进入一个 ubuntu15.10 系统的容器
root@94490b385929:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@94490b385929:/# cat /proc/version
Linux version 5.4.0-182-generic (buildd@lcy02-amd64-069) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)) #202-Ubuntu SMP Fri Apr 26 12:29:36 UTC 2024
root@94490b385929:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
# 退出当前的容器,返回到当前的主机中
root@94490b385929:/# exit
exit
docker run -i -t ubuntu:15.10 /bin/bash
:基于镜像ubuntu:15.10启动一个容器,参数为以命令行模式进入该容器
-i -t
也可以缩写成-it
,参数解释:
- -t: 在新容器内指定一个伪终端或终端。
- -i: 允许你对容器内的标准输入 (STDIN) 进行交互。
通过上面的命令启动一个docker容器后,执行exit会退出该容器,并且该容器也会停止。通过
docker ps -a
也可以看到该容器,只是该容器已经处于停止状态
启动容器(后台模式)
root@iZuf63y0r6z2tc37u0q5l8Z:~# docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
2e35da88847a6fef3ec63954488e7c0cc2bdbba5549e6ad317e3b2a373ceabff
root@iZuf63y0r6z2tc37u0q5l8Z:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2e35da88847a ubuntu:15.10 "/bin/sh -c 'while t…" 3 seconds ago Up 3 seconds
在输出中,我们没有看到期望的 "hello world",而是一串长字符 2e35da88847a6fef3ec63954488e7c0cc2bdbba5549e6ad317e3b2a373ceabff。这个长字符串叫做容器 ID,对每个容器来说都是唯一的。通过docker ps查看正在运行的docker容器。参数解释:
CONTAINER ID: 容器ID
IMAGE: 使用的镜像
COMMAND: 启动容器时运行的命令
CREATED: 容器的创建时间
STATUS: 容器状态。状态有7种:
- created(已创建)
- restarting(重启中)
- running 或 Up(运行中)
- removing(迁移中)
- paused(暂停)
- exited(停止)
- dead(死亡)
PORTS: 容器的端口信息和使用的连接类型(tcp\udp)
NAMES: 自动分配的容器名称
在宿主主机内使用 docker logs 命令,查看容器内的标准输出
docker logs 2e35da88847a
# 等同tail -f
docker logs -f 2e35da88847a
停止该docker容器
docker stop 2e35da88847a
进入容器
在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入
- docker attach:如果从这个容器退出,会导致容器的停止
- docker exec:推荐使用,因为此命令会退出容器终端,但不会导致容器的停止
docker exec -it 某容器id /bin/bash
导入导出容器
# 将容器导出到本地文件test.tar中
docker export 某容器id > test.tar
# 导入为镜像
cat ./test.tar | docker import - test/ubuntu:v1
# 通过指定 URL 或者某个目录来导入
docker import http://example.com/exampleimage.tgz example/imagerepo