Docker学习笔记
[TOC]
Docker学习前言
本系列主要为自己学习Docker做一点记录,很多内容是对网络上很多长文的概括,也许有内容说法经过简述并不严谨,只是为方便自己的理解或使用,若有不一样的见解,欢迎提出。
本系列旨在以最少的内容入门Docker。
Docker常见术语
具体含义会在后面解释
- 镜像(
Image
) - 容器(
Container
) - 仓库(
Repository
) - 数据卷(
Volume
) - 虚悬镜像(
dangling image)
Docker概述
为什么用Docker
我们经常遇到因为环境不一样而导致程序运行出错,而Docker的出现解决了这个问题。
Docker是一种虚拟化方式,Docker有很多优势:
- 高效的系统资源利用率
- 启动快
- 统一的运行环境
- 持续的交付和部署
- 轻松便捷的迁移
- 简便的维护和扩展
Docker的基本概念
可以说,Docker主要由三个部分组成。
- 镜像(
Image
) - 容器(
Container
) - 仓库(
Repository
)
Docker镜像
Docker镜像是一个特殊的文件系统,其包含了容器运行所需的程序、库、资源等,也包含了运行时准备的一些配置参数。镜像不包含任何动态数据,也就是其内容构建之后也不会被改变。
Docker镜像是分层存储的,构建时是一层一层的,这种特性也使它的复用、定制变得容易。
Docker容器
镜像(Image
)和容器(Container
)的关系,类似于面向对象程序设计中的类
和对象
的关系。容器是镜像运行时的实体,容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但这个容器进程运行于属于自己的独立的命名空间。容器内的进程是运行在一个隔离的环境里。
容器和镜像一样,分层存储。每一个容器运行时是以镜像为基础层,在其上创建一个当前容器的存储层,这个为容器运行时读写而准备的存储层称为容器存储层。(有点类似于电脑的内存)
容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume
)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。
Docker仓库
对于用过GitHub仓库就很好理解,镜像和仓库的关系就类似于用 git管理的项目
与GitHub仓库
之间的关系。
每个仓库可以包含多个标签,每个标签对应一个镜像,我们可以通过 <仓库名>:<标签>
的格式来指定具体是这个软件哪个版本的镜像。
Docker安装
Docker官方为了简化安装流程,提供了一套简便的安装脚本:
curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun
测试是否安装完成。
docker -v
Docker镜像
拉取镜像
docker pull [选项] <镜像>
其中<镜像>的完整格式是
[<域名/IP>[:端口号]/]<用户名>/<软件名>[:标签]
前面这一段 IP 加端口 是Docker镜像仓库地址,不写默认为Docker Hub。
中间<用户名>/<软件名>
这一段为仓库名,类似于GitHub某用户下的某个项目,用户名不写则默认为官方镜像library
。
后面一段标签指定拉取的版本,不写默认为latest
如:
docker pull ubuntu
等价于
docker pull library/ubuntu:latest
查看镜像
docker images
# 或者
docker image ls
若存在仓库名和标签均为<none>
的,这类镜像称为虚悬镜像(dangling image)
一般来讲,这类镜像已经失去价值,我们可以以下指令列出该类镜像或删除:
docker image ls -f dangling=true #列出虚悬镜像
docker image prune #删除虚悬镜像
查看所有镜像(包括中间层镜像):
docker image ls -a
删除本地镜像
命令格式:
docker image rm [选项] <镜像>
其中<镜像>
可以是镜像短ID
、镜像长ID
、镜像名
、镜像摘要
Docker容器
查看已有容器
列出运行中的容器
docker ps
列出所有容器
docker ps -a
启动
新建并启动
我们可以用一下命令新建并启动容器
docker run [选项] <镜像名>
#例如:
docker run -it ubuntu /bin/bash
-i
是以交互模式操作,-t
终端,二者可以合起来用-it
,若要退出输入exit
即可。
当利用 docker run
来创建容器时,Docker 在后台运行的标准操作包括:
-
检查本地是否存在指定的镜像,不存在就从公有仓库下载
-
利用镜像创建并启动一个容器
-
分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
-
从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
-
从地址池配置一个 ip 地址给容器
-
执行用户指定的应用程序
-
执行完毕后容器被终止
启动已终止的容器
docker start <容器>
其中,<容器>
可以是容器名
、容器长ID
、容器短ID
后台运行
docker run -d <镜像名>
-d
后台运行
(注意:即使没有-d
,容器也是会长久运行的,区别只在于是否会将容器内的输出信息显示在当前终端内)
获取容器内输出信息
docker logs <容器>
终止
docker stop <容器>
进入容器
docker attach <容器名>
注意:在这个命令进入容器内,在stdin中exit会使容器停止。
docker exec -it 容器名 bash
注意:在docker exec
下进入容器,在stdin中exit不会导致容器停止。
迁移
导出容器
docker export <容器> > <文件名>.tar
导入
docker import <文件名>.tar [用户名/]<软件名>[:标签]
我们也可以使用docker load
来导入镜像存储文件到本地镜像库,也可以使用docker import
来导入一个容器快照到本地镜像库。二者的区别仅在于容器快照会丢掉所有历史记录和元数据信息(标签等信息),可以在导入时重新定义,如上面的指令一样。而镜像存储文件会保存完整记录,所以体积也要大。
删除容器
删除一个处于终止状态的容器:
docker rm <容器>
Docker数据卷
数据卷特性
数据卷
(volume)是一个可供一个或多个容器使用的特殊目录,有以下特性:
-
数据卷
可以在容器之间共享和重用 -
对
数据卷
的修改会立马生效 -
对
数据卷
的更新,不会影响镜像 -
数据卷
默认会一直存在,即使容器被删除
数据卷
创建一个数据卷
docker volume create <数据卷名>
查看数据卷
查看所有数据卷:
docker volume ls
查看指定数据卷信息:
docker volume inspect <数据卷名>
启动一个挂载数据卷的容器
我们可以在docker run
的时候使用--mount
或者-v
挂载数据卷到容器,这里推荐使用--mount
。
使用 -v
参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,而使用 --mount
参数时如果本地目录不存在,Docker 会报错。
docker run -d -P \
--name web \
# -v /src/webapp:/usr/share/nginx/html \
--mount type=bind,source=/src/webapp,target=/usr/share/nginx/html \
nginx:alpine
注意:目录需要用绝对地址。
在主机中可以用以下命令查看容器信息:
docker inspect <容器>
数据卷
信息在列出的“Mounts”关键字下面。
删除数据卷
docker volume rm <数据卷名>
数据卷生命周期独立于容器。
若在删除容器时想同时移除数据卷:
docker rm -v <容器>
想清理无主的数据卷:
docker volume prune
Docker网络
外部访问容器
在容器运行网络应用时,我们希望能够访问这些应用,可以在docker run
时加上-P
或-p
参数来指定端口映射。
使用-P
时,Docker会随机一个49000 ~ 49900
的端口到内部容器开放的端口(不推荐使用)。
-p
则是指定端口映射,主机的一个指定端口只可以绑定一个容器。
端口映射
-p
端口映射有三种格式:
ip:hostport:containerport #指定ip、指定宿主机port、指定容器port
ip::containerport #指定ip、未指定宿主机port(随机)、指定容器port
hostport:containerport #未指定ip、指定宿主机port、指定容器port
docker run -d -p 8080:80 <镜像>
默认本地的所有地址的8080端口映射到容器的80端口
docker run -d -p 127.0.0.1::80 <镜像>
本地的127.0.0.1地址的随机一个端口映射到容器的80端口
docker run -d -p 127.0.0.1:8080:80 <镜像>
本地的127.0.0.1地址8080端口映射到容器的80端口
注意:端口协议默认为tcp,可以在映射格式后加/udp
改为udp协议
查看容器端口映射配置
docker port <容器>
容器互联
新建网络
docker network create -d bridge <网络名>
-d
参数指定Docker网络类型,有bridge
、overlay
。
连接容器
运行两个容器并连接到你创建的网络:
docker run -it --name ubuntu1 --network <网络名> ubuntu bash
docker run -it --name ubuntu2 --network <网络名> ubuntu bash
试着在一个容器里ping一下另外一个容器,查看是否能成功连接。
如果有多个容器之间需要互相连接,推荐使用Docker Compose
,之后会讲到。
Docker三剑客
Docker三剑客Docker Compose
、Docker Machine
、Docker Swarm
分别是Docker官方开源的三个项目。有着不同的功能:
Docker Compose
负责实现对 Docker 容器集群的快速编排。Docker Machine
负责在多种平台上快速安装 Docker 环境。Docker Swarm
提供 Docker 容器集群服务,是 Docker 官方对容器云生态进行支持的核心方案。
这里主要讲一下Docker Compose
,其余如果有兴趣可以自行去了解。
Docker Compose
Compose简介
Docker Compose
很好的帮助我们完成需要多个容器相互配合来完成某个任务的需求。
我们需要知道Compose
中有两个重要的概念:
-
服务 (
service
):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。 -
项目 (
project
):由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml
文件中定义。
Compose
的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。
Compose
项目由 Python 编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose
来进行编排管理。
Compose安装
安装十分简单,直接apt安装就行
sudo apt install docker-compose
也可以在 官方 GitHub Release 处直接下载编译好的二进制文件即可。
#linux-x86_64
sudo curl -L https://github.com/docker/compose/releases/download/2.6.0/docker-compose-linux-x86_64 > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
#linux-armv7
sudo curl -L https://github.com/docker/compose/releases/download/2.6.0/docker-compose-linux-armv7 > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Compose 模板文件
Docker Compose
是通过定义docker-compose.yml
文件来定义组成应用的服务的,以便它们可以在隔离的环境中一起运行。
一个docker-compose.yml
形如:
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
运行compose项目
docker-compose up