Docker 使用指北
Introduction
软件开发最大的麻烦事之一,就是环境配置。用户计算机的环境不同,可能导致软件在开发环境中能运行,而到了生产环境无法运行的情况。
用户必须保证两件事:操作系统的设置,各种库和组件的安装。只有它们都正确,软件才能运行。举例来说,安装一个 Python 应用,计算机必须有 Python 引擎,还必须有各种依赖,可能还要配置环境变量。
环境配置如此麻烦,换一台机器,就要重来一次,旷日费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。
这个问题的一种解决方式是使用虚拟机,比如我们常用的 WSL,就是在 Windows 系统中运行 Linux 虚拟系统的例子。但是,这样做的资源占用多,要重新配置一个全新操作系统的冗余步骤多,启动起来也十分缓慢。于是,Linux 发展出了另一种虚拟化技术:虚拟容器。
Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。
Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。
Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。
总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
Installation
- Windows https://docs.docker.com/desktop/windows/install/
- Linux https://docs.docker.com/engine/install/ubuntu/
Concepts
- 镜像(Image):类似于虚拟机中的镜像,是一个包含有文件系统的面向 Docker 引擎的只读模板。任何应用程序运行都需要环境,而镜像就是用来提供这种运行环境的。例如一个 Ubuntu 镜像就是一个包含 Ubuntu 操作系统环境的模板,同理在该镜像上装上 Apache 软件,就可以称为 Apache 镜像。
- 容器(Container):类似于一个轻量级的沙盒,可以将其看作一个极简的 Linux 系统环境(包括 root 权限、进程空间、用户空间和网络空间等),以及运行在其中的应用程序。Docker 引擎利用容器来运行、隔离各个应用。容器是镜像创建的应用实例,可以创建、启动、停止、删除容器,各个容器之间是是相互隔离的,互不影响。注意:镜像本身是只读的,容器从镜像启动时,Docker 在镜像的上层创建一个可写层,镜像本身不变。
- 仓库(Repository):类似于代码仓库,这里是镜像仓库,是 Docker 用来集中存放镜像文件的地方。注意与注册服务器(Registry)的区别:注册服务器是存放仓库的地方,一般会有多个仓库;而仓库是存放镜像的地方,一般每个仓库存放一类镜像,每个镜像利用 tag 进行区分,比如 Ubuntu 仓库存放有多个版本(12.04、14.04 等)的 Ubuntu 镜像。
Images
对镜像的基本操作总结:
- 官方注册服务器(Registry):https://hub.docker.com/
- 搜索某个镜像:
docker search <image>
- 将某个镜像下载到本地:
docker pull <image>
// 如果不加 tag 默认使用 latest 镜像docker pull <image>:<tag>
- 查看当前下载的镜像信息:
docker images
- 新建自定义镜像的方法
方法 1:利用镜像启动一个容器后修改,再进行 commit
[root@xxx ~]# docker run -it centos:latest /bin/bash # 启动一个容器
[root@72f1a8a0e394 /]# # 这里命令行形式变了,表示已经进入了一个新环境
[root@72f1a8a0e394 /]# git --version # 此时的容器中没有 git
bash: git: command not found
[root@72f1a8a0e394 /]# yum install git # 利用 yum 安装 git
......
[root@72f1a8a0e394 /]# git --version # 此时的容器中已经装有 git 了
git version 1.8.3.1
然后按下 Ctrl+D 或者输入 exit 退出容器,然后查看当前所有容器:docker ps -a
。这里将容器转化为一个镜像,即执行 commit 操作,完成后可使用 docker images 查看:
[root@xxx ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
72f1a8a0e394 centos:latest "/bin/bash" 9 minutes ago Exited (0) 3 minutes ago angry_hodgkin
[root@xxx ~]# docker commit -m "Commit Message" -a "UserInfo" <Container ID> <user>/<repo>:<tag>
[root@xxx ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<user>/<repo> git 52166e4475ed 5 seconds ago 358.1 MB
centos latest 0584b3d2cf6d 9 days ago 196.5 MB
此时 Docker 引擎中就有了我们新建的镜像 <user>/<repo>:<tag>
,此镜像和原有的 CentOS 镜像区别在于多了个 Git 工具。此时我们利用新镜像创建的容器,本身就自带 Git 了。
方法 2:使用 Dockerfile
Dockerfile 可以理解为一种配置文件,用来告诉 docker build
命令应该执行哪些操作。一个简易的 Dockerfile
文件如下所示:
# 说明该镜像以哪个镜像为基础
FROM centos:latest
# 构建者的基本信息
MAINTAINER <user>
# 在 build 这个镜像时执行的操作
RUN yum update
RUN yum install -y git
# 拷贝本地文件到镜像中
COPY ./* /usr/share/gitdir/
# Expose 对应端口,允许外部连接
EXPOSE 3000
官方教程链接:https://docs.docker.com/engine/reference/builder/
有了 Dockerfile
之后,就可以利用 build
命令构建镜像了:
[root@xxx ~]# docker build -t="<user>/<repo>:<tag>" .
其中 -t 用来指定新镜像的用户信息、tag 等。最后的点表示在当前目录寻找 Dockerfile
。
删除容器或镜像
- 删除容器:
docker rm container_name/container_id
- 删除镜像:
docker rmi image_name/image_id
- 删除镜像前必须先删除以此镜像为基础的容器。
- 删除容器:
镜像的保存与加载
- 保存镜像:
docker save -o centos.tar <user>/<repo>:<tag>
- 加载镜像:
docker load -i centos.tar
- 保存镜像:
Containers
- 启动容器:
docker run [Options] <Image> [Command]
-d
:Run container in background and print container ID-e
:Set environment variables-i
:Keep STDIN open even if not attached-p <host>:<container>
:Publish a container’s port to the host-t
:Allocate a pseudo-TTY--name
:Assign a name to the container-v <host>:<container>
:Mount host_path to container_path- 常用命令:
docker run -itd centos:latest /bin/bash
- 如果想让容器一直运行,而不是停止,可以使用快捷键 Ctrl+P Ctrl+Q 退出,此时容器的状态为 Up。
- 启动容器:
docker start <container>
- 停止容器:
docker stop container>
- 重启容器:
docker restart <container>
- 进入已启动的容器:
docker attach <container>
- 复制文件:
docker cp <container>:<path> <host_path>
Repositories
- 官方镜像服务器:https://hub.docker.com
- 登录 DockerHub:
docker login
- 推送本地镜像:
docker push <username>/<repo>:<tag>
username
必须与你 Docker Hub 中的用户名一致
- 拉取远端镜像:
docker pull <username>/<repo>:<tag>