Docker 学习笔记(一):基础命令

仅为个人查阅使用,要学习 Docker 的话,推荐看这份文档:《Docker — 从入门到实践》

P.S. 大多数的 docker container xxx/docker image xxx 命令,都有相对应的缩写方式:docker xxx

零、安装 docker

参见 《Docker — 从入门到实践—安装》,包括各 Linux 发行版、Windows、MacOS

国内加速器: https://get.daocloud.io/#install-compose,包含 Linux 安装加速、Hub 镜像仓库加速。(但它的 Windows 加速版本太老,别用)

一、基本概念

要构建并运行一个 Docker 容器,有这样几个步骤:

  1. 编写 Dockerfile,然后通过 build 命令从 Dockerfile 构建镜像
    1. 镜像是分层构建,分层存储。这使得镜像的复用、定制变的更为容易。
    2. 镜像不包含任何动态数据,其内容在构建之后就不会被改变。因此它对运维很友好,可以实现一次 build 到处运行。
  2. 通过 run 命令启动该容器。(镜像仓库后面再记)
    1. 镜像内容是静态的,而容器是动态的!
    2. 每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层。可以称这个为容器运行时读写而准备的存储层为 容器存储层
    3. 容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。
    4. 所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
  3. 用 login 命令登录到 Docker 的镜像仓库(私人的或者公共的),然后通过 push 命令将构建好的镜像推送上去。
  4. 在别的机器上 pull 镜像下来,通过 docker run xxx 命令运行。

二、Docker 基础命令

1. 获取镜像

通过 pull 命令从仓库中获取镜像:

# 格式
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]

# e.g. 1:从公共仓库拉 nginx 的镜像
# 下列两条命令效果相同,默认从 library (官方镜像)找镜像,tag 默认为 latest(最新版本)
docker pull library/nginx:latest
docker pull nginx

# e.g. 2:从公共仓库中,拉取个人上传的镜像
docker pull <username>/myblog:latest

# e.g. 3:从私人仓库拉取 ryan 项目下,名为 myblog 的镜像
docker login reg.myharbor.com:4321  # 私人仓库一般都需要先登录,会将登录信息保存到本地
docker pull reg.myharbor.com:4321/ryan/myblog

自己编写 Dockerfile,然后通过 Dockerfile 构建镜像(Dockerfile 的语法后面再细说):

# --tag 可以缩写成 -t,用于指定镜像的 [镜像名:<tag>],其中 <tag> 可省略。
docker build --tag friendlyhello .  # 使用当前目录下的 Dockerfile 构建镜像,并且`镜像名:tag`为 `friendlyhello:latest`

2. 查看/删除镜像

查看镜像列表:

docker image ls -a     # 列出当前机器上的所有镜像
docker images -a       # 上一条命令的缩写

docker images -a <image name>  # 查找名为 <image name> 的镜像

删除镜像:

docker image rm <image id>
docker image rm <image name>:<tag>  # 删除 <image name> 镜像的一个 tag

docker rmi <xxx>  # `docker image rm <xxx>` 的缩写

docker image ls -f dangling=true  # 列出所有虚悬镜像(即仓库名和 tag 都为 none 的镜像)
docker image prune  # 清除所有未被使用的虚悬镜像(被依赖了的虚悬镜像无法直接清除,见后)

docker image rm $(docker image ls -a -q)  # 删除本机的所有镜像(危险操作)
docker system prune  # 删除所有停止的容器+虚悬镜像+未被使用 network+构建缓存
docker system prune --all # 除了上述数据之外,还要删除所有未被容器使用的镜像

如果一个正常的镜像,或者某个容器依赖了某些虚悬镜像,那这些虚悬镜像就不能被直接删除。你需要先删除掉那个上层的镜像或者容器。

删除该上层镜像时,所有只被它依赖了的虚悬镜像也会被自动清除掉。但是删除上层容器后,还需要手动用 docker image prun 清除被它使用了的虚悬镜像。

3. 启动容器

  1. docker run: 从指定镜像新建一个容器并运行命令,然后终止运行。标准流程如下:
    • 检查本地是否存在指定的镜像,不存在就从公有仓库下载(对应 docker image pull
    • 利用镜像创建并启动一个容器(对应 docker container create
    • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
    • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
    • 从地址池配置一个 ip 地址给容器
    • 执行用户指定的应用程序(对应 docker container start
    • 执行完毕后容器被终止(对应 docker container stop
# 在 ubuntu 18.04 中输出 Hello World
# --rm 表示,容器终止运行后,自动删除该容器
# 此外,还有 --env 设置环境变量,-p 设置端口映射,--volume 设置数据卷
# --net 设置网络连接类型
docker run --rm ubuntu:18.04 /bin/echo 'Hello world'

docker run -it --user=root <image:tag> bash # 以 root 身份运行 bash(不要去用 su root,然后到处找 root 的密码了。。)

# 进入容器的 bash 终端
# -i 使容器的 stdin 保持打开,-t 为容器分配一个伪 tty。
# 结合使用上述两个选项 `-it`,效果类似 ssh 远程连接。
docker run -it ubuntu:18.04 /bin/bash

# P.S. 其实只需要 -i 参数,就能和容器进行交互了,敲命令能得到回复。
# -t 添加的伪终端,感觉只是在每个命令行开头加了个 `root@25d5c233769b:/# ` 这样的提示符。
  1. docker run -d:使新建的容器在后台运行
# 在后台启动一个 nginx 容器,提供静态网站访问功能,或者做代理
# -d 表示在后台运行该容器,--rm 使容器在终止后被自动删除
docker run -d --rm my-nginx:latest

# --restart=always 容器意外退出时,总是自动重启。以保证服务总是可用。
# --name my-blog  为容器取个有意义的名字,可在任何命令中,用该名字替换 container id 使用
docker run --rm -d -restart=always --name my-blog my-nginx:latest

# 前台运行的容器,stdout 会被定向到本机的 stdout,所以能直接看到命令的输出
# 而后台运行的容器,就需要通过下面的命令查看输出了
docker logs <container id / container name>  # 查看指定容器的 logs,更详细的参数请 man
docker logs <container id / container name> | vim -  # 通过 vim 查看容器日志,可以方便地按行跳转、全文搜索。
docker logs -f <container id / container name>  # 持续地输出容器的日志(ctrl-c 退出)
  1. 查看容器列表、启动/终止容器、删除容器
docker container ls -a  # 列出所有容器
docker ps -a  # 上一条命令的缩写

docker container create --name <container name>  <image>:<tag> [command]  # 从指定镜像新建容器,但是不立即运行。

docker container start <container id / container name>   # 启动一个已经终止运行的容器
docker container stop <container id / container name>   # 终止一个正在运行的容器(该容器可能在后台工作,也可能是正被别的 shell 运行)

docker container rm  <container id / container name>    # 删除一个未运行的容器
docker container rm -f <container id / container name>   # 强制删除容器,即使该容器正在运行

docker container prune  # 清理掉所有已终止的容器

docker rm -f $(docker ps -aq)  # 强制删除掉所有的容器!可用于清理系统。

docker [start|stop|rm] <xxx>  # 上述命令的缩写,container 可省略
  1. 登入容器:
# 1. 使用 attach 命令登入(不推荐!!)
# 将容器的 stdin/stdout/stderr 与当前终端接驳,容器切换到前台运行。
# 特别注意的是,因为容器切换到了前台运行,退出会导致容器终止!因此才不推荐用此命令。
docker container attach <container id / container name>`  # 可缩写成 `docker attach xxx`

# 2. 使用 exec 命令登入(推荐方式)
docker exec -it <container id / container name> bash  # 使用默认用户登录
docker exec -it --user=root <xxx>  # 以 root 身份登入容器(不要去用 su root,然后到处找 root 的密码了。。)
  1. 查看容器的各项数据
docker container stats  <container id / container name>  # 查看容器的 CPU/RAM 使用率,网络IO速率等参数
docker container logs  <container id / container name>  # 查看容器日志,一般都是 CMD/ENTRYPOINT 命令的日志
docker container diff <container id / container name>   # 查看容器层相对镜像的变动(A-added,D-deleted,C-changed)

docker container kill  <container id / container name>  # 强制终止容器,发送终止信号给容器。(只是发信号过去,不一定成功。。)

docker container ls --size  # 列出所有容器,显示各容器的 disk 占用

容器/镜像中数据的导入和导出

# 1. 将容器中的指定路径(文件夹) copy 出来
# 可以指定存放路径(若路径不存在,会自动创建),也可以通过管道以流的方式传输给下个程序
docker container cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-   
# 2. 将本机的数据拷贝进容器,可以是路径,也可以通过管道以流的方式传输到容器中。(用 tar -ax 就能正确将流转成原来的文件)
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

# 3. 存取镜像中的数据
# 方法一:直接在 Dockerfile 中使用 COPY --from=<image name>:<tag> <src path> <dest path>
# 方法二:先使用 docker create 为镜像新建容器层,再用 docker cp 命令导入/导出数据。

4. 镜像/容器的导入和导出

4.1 镜像的导入导出

镜像可以通过中心仓库进行分享,但是有些情况下,我们只想快速地将镜像分享给某台机器。这就需要用到镜像的导入导出功能了:

# a. 将指定镜像导出为 tar 文件
# 注意:如果同名则会覆盖(没有警告)
docker save <imagename>:<tag> -o <filename>

# 使用 gzip 进一步压缩
docker save <imagename>:<tag> | gzip > <imagename>-<tag>.tar.gz

# b. 从指定文件加载镜像
docker load -i <imagename>-<tag>.tar.gz  # 不需要先解压

上述导入导出命令,结合 ssh,就能完成镜像的快速分享:

docker save <镜像名> | bzip2 | pv | ssh <用户名>@<主机名> 'cat | docker load'

# pv:即 Pipe Viewer,意思是通过管道显示数据处理进度的信息。一般需要自行安装。
# yay -S pv 或 sudo apt-get install pv 或 yum install pv

4.2 容器的导入和导出(不推荐)

容器导出后再导入到镜像中,环境变量和一些基本的配置信息丢失了。所以最好还是不用使用这个功能,前后不一致,从镜像入手才是正确的方式。

虽然说容器层不应该保存任何动态数据,
但是总有特殊情况(或者说太菜),我们把一些必需的东西放进了容器层,现在要使容器能在另一台机器上运作。

这时候,就需要做容器的导入导出了:

# 将容器的当前快照导出为文件
docker export [container id / container name] > ubuntu.tar

# 从文件将容器快照导入为镜像,
# 注意!!!是导入成了镜像!并且为这个镜像指定了 [name:tag]
cat ubuntu.tar | docker import - test/ubuntu:v1.0

容器导出的镜像,环境变量和一些基本的配置信息都会丢失,而且 ENTRYPOINT/CMD 信息也会丢失,运行(run)时还需要手动指定命令。

感觉是相当不好用。

Docker 仓库

docker login <repo-host:port>  # 登录到指定的仓库,默认登录到 docker hub
docker logout <repo-host:port>   # 登出指定仓库

docker search <image name>  # 在 Docker Hub 中搜索镜像

参考

遇到过的问题

posted @ 2019-07-14 13:15  於清樂  阅读(573)  评论(0编辑  收藏  举报