Docker使用/镜像制作

1.Docker基础

1.1 Docker 介绍

Docker解决了什么?

在别的电脑上不能跑的问题:

开发者经常遇到项目在自己的机器上能跑,部署到服务器上就出问题。Docker把运行环境也打包进去,确保“哪里都能跑”。

环境配置繁琐

安装依赖、配置系统库等工作复杂、容易出错。Docker一次配置好,别人直接使用镜像就可以。

版本冲突问题

比如两个项目用不同版本的Python、MySQL,传统的方式难以共存,Docker可以让它们分别在不同的容器里运行,互不影响。

开发、测试、部署一致性

Docker可以让开发环境、测试环境、线上环境完全一致,大大减少线上bug。

跨平台部署

Docker镜像支持构建一次,到处运行,跨平台部署变简单。

Docker是什么?

Docker 是一个开源的应用容器引擎,基于 Go 语言,并遵从 Apache2.0 协议开源。它可以让开发者打包应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 、windows等机器上,也可以实现虚拟化。Docker 可用于开发应用、交付应用、运行应用等场景。
容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。Docker 允许用户将基础设施中的应用单独分割出来,形成更小的部分容器,从而提高软件交付速度。

Docker与虚拟机对比

如果物理机是一栋住宅楼,虚拟机就是大楼中的一个个套间,而容器技术就是套间里的一个个隔断。

虚拟化技术不同

  • VMware Workstation, VirtualBoX

    硬件辅助虚拟化: 是指通过硬件辅助支持模拟运行环境,使客户机操作系统可以独立运行,实现完全虚拟化的功能。

  • Docker

    操作系统层虚拟化: 这种技术将操作系统内核虚拟化,可以允许使用者空间软件实例被分割成几个独立单元,在内核中运行,而不是只有一个单一实例运行。软件实例,也被称为是一个容器、虚拟引擎、虚拟专用服务器。每个容器的进程是独立的,对使用者来说,就像是在使用自己的专用服务器。

应用场景不同

  • 虚拟机更擅长于彻底隔离整个运行环境。如:云服务提供商通常采用虚拟机技术隔离不同的用户。
  • Docker通常用与隔离不同的应用,例如前端、后端以及数据库。

资源的使用率不同

  • 虚拟机启动需要数分钟,而Docker容器可以数毫秒内启动。由于没有臃肿的操作系统,Docker可以节省大量的系统资源。

1.2 Docker架构与核心组件

IMG_0774

客户端

  • linux终端

通过终端,操作一些docker命令,完成对docker的操作

docker服务器

  • 是一个守护进程,不能和用户交互,在后台运行
  • 管理容器和镜像

docker镜像

  • 理解为一个可执行程序
  • 镜像可以启动,启动之后就是容器
  • 镜像一般不需要使用者制作

docker容器

  • 占用内存、cpu资源
  • 镜像可以启动,启动之后就是容器

镜像仓库

  • docker官方提供了一个镜像仓库 docker hub

2.Docker镜像管理

IMG_0788

2.1 镜像的搜索/获取/查看

镜像搜索

1
2
3
4
5
6
#命令
$ docker search 镜像的名字
#字段关键字
STARS - 下载量
OFFICIAL - 是否官方出品
AUTOMATED - 是否自动化编译(通过dockerfile制作)

下载镜像

1
2
3
4
#下载远程仓库(如Docker hub)中的镜像
$ docker pull 镜像名
#镜像存储目录
/var/lib/docker/image

查看镜像

1
2
3
4
5
6
#命令
#查看所有镜像
$ docker images
$ docker image ls
#查看特定镜像
$ docker image 镜像的名字

2.2 镜像别名/删除

镜像别名

1
2
$ docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
#镜像ID不改变

镜像删除

1
2
3
:$ docker rmi 镜像名字/镜像ID
#如果镜像有别名,必须根据名字:tag(如果tag不是latest,如果是则可以省略)
#没有别名,可以 名字/ID 删除

镜像的导入导出

1
2
3
4
5
6
7
8
9
10
11
$ docker save [OPTIONS] IMAGE [IMAGE...]
- OPTIONS:
-o,--output string
导出的文件名
- IMAGE
本地镜像仓库中的镜像名

$ docker load [OPTIONS]
-i,--input string
string: 通过save导出之后的文件名
$ docker load < string
IMG_0788

3.Docker容器管理

IMG_0798

docker将镜像文件启动,得到一个容器,一个容器可以被看做一个操作系统

3.1 容器的查看/创建/启动

  • 容器查看
1
2
3
4
5
#命令
$ docker ps
#关键字
COMMAND: 启动之后默认执行的第一个命令
PORTS: 容器和宿主机对应的映射端口
  • 容器创建
1
2
3
4
5
6
7
8
9
10
#容器被创建,但是还不能使用,需要启动
$ docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
- OPTIONS:
-i,--interactive: 创建的容器是否关联标准输入
-t,--tty: 是否给这个容器分配终端
--rm: 容器停止后是否自动销毁
--name: 给容器的名字,没指定随机生成
- IMAGE: 基于哪个镜像启动
- [COMMAND] [ARG...]
容器启动之后,指定一个默认执行的shell命令,根据实际情况指定
  • 创建新容器并启动
1
2
3
4
5
6
7
8
9
10
11
#创建并运行容器run == create + start
$ docker run [OPTIONS] IMAGE [COMMAND] [ARGS...]
- OPTIONS:
-i,--interactive:
-t,--tty:
--rm:
--name:
-d,--detach: 容器启动后是否为守护进程(后台运行)
- IMAGE:
- [COMMAND] [ARG...]
容器启动之后,指定一个默认执行的shell命令,根据实际情况指定

3.2 容器的暂停/重启

  • 暂停
1
$ docker pause 容器名/容器ID
  • 取消暂停
1
$ docker unpause 容器名/容器ID
  • 重启
1
$ docker restart 容器名/容器ID

3.3 容器的关闭/终止/删除

  • 关闭
1
2
3
#延时关闭,默认10s
$ docker stop 容器名/容器ID
-t,--time: 指定时长后关闭
  • 终止
1
2
#立刻关闭,不会延时
$ docker kill 容器名/容器ID
  • 删除
1
2
3
4
$ docker rm 容器名/容器ID
-f,--force: 可删除正在运行的容器
#批量删除容器
$ docker rm -f $(docker ps -aq)

3.4 容器的进入/查看

  • 进入容器
1
2
3
$ docker exec 参数 容器名 bash
-i: 关联标准输入
-t: 分配一个操作终端
  • 查看容器的详细信息
1
$ docker inspect 容器名/容器ID
  • 查看容器的端口信息
1
$ docker port 容器名/容器ID

IMG_0798

4.Docker数据管理

4.0 数据拷贝

1
2
3
#容器和宿主机之间的数据拷贝
$ docker cp 宿主机目录/文件 容器/容器ID:容器路径
$ docker cp 容器/容器ID:容器目录/文件 宿主路径

4.1 数据卷和使用

数据卷是什么

宿主机的存储目录,要将目录中的数据和docker容器进行数据共享

数据卷在docker中的应用

挂载目录

1
2
3
4
5
6
7
8
9
10
11
12
13
#挂载的时机:
#1.容器被创建的时候
$ docker create
#2.容器被创建并运行的时候
$ docker run
#添加需要挂载的卷
-v,--volume

#形成映射关系
$ docker run -itd --name -v 宿主机的路径:容器的路径 test ubuntu bash
-宿主机的路径:必须使用绝对路径,如果宿主机器路径不存在,会自动创建
-容器的路径:如果不存在会被自动创建

权限问题

通过-v进行数据卷挂载,默认是读写的挂载方式

  • 权限是限制容器的,rw
  • 可以修改权限,改为只读:ro

$ docker run -itd --name -v 宿主机的路径:容器的路径:ro test ubuntu bash

4.2 数据卷容器和使用

数据卷容器

就是一个普通的容器,在这个容器中提供了一个挂载目录(共享目录)

  • /数据卷容器只要被创建出来就可以使用: docker createdocker run

创建数据卷容器

1
2
3
docker create -itd --name 容器名 -v 容器的挂载目录 镜像名 shell命令
docker run -itd --name 容器名 -v 容器的挂载目录 镜像名 shell命令
- 容器的挂载目录: 如果不存在,就会自动创建

数据卷容器的挂载使用

1
2
3
4
5
6
7
8
9
10
#挂载数据卷容器的参数
--volumes-from 数据卷容器的名字/ID
#1.创建数据卷容器
docker run -itd --name containsVolume -v /volume ubuntu bash
#2.启动测试容器1,挂载数据卷容器
docker run -itd --name test1 --volumes-from containsVolume ubuntu bash
#3.启动测试容器2,挂载数据卷容器
docker run -itd --name test2 --volumes-from containsVolume ubuntu bash
#4.测试数据是否共享
docker exec -it test1 bash

数据卷容器数据卷备份

备份

1
2
3
4
5
6
#创建一个临时新容器,挂载到数据卷容器上,并且和宿主机目录形成映射关系
docker run -itd --rm --name backup --volumes-from containsVolume -v /home/backup:/xxx \
#将volume中的内容拷贝到xxx目录
ubuntu cp /volume /xxx -r
#或者压缩
ubuntu tar zcvf /xxx/backup.tar.gz /volume

还原

1
2
3
4
5
6
#创建一个临时新容器,挂载到数据卷容器上,并且和宿主机目录形成映射关系
docker run -itd --rm --name backup --volumes-from containsVolume -v /home/backup:/xxx \
#将xxx目录拷贝到volume目录
ubuntu cp /xxx /volume -r
#或者解压缩
ubuntu tar zxpf /xxx/backup.tar.gz -C /

5.Docker网络管理

5.1 docker端口映射

随机端口映射

1
2
3
#创建容器时启动端口映射
docker run -itd -P --name mynginx nginx
#在宿主机随便找一个没有占用的空闲端口和容器的80端口进行映射

指定端口映射/指定多端口映射

1
2
3
4
5
6
#使用的参数
docker run -itd -p xxx --name mynginx nginx
-p 宿主机的IP:宿主机的端口:容器的端口
宿主机的端口:容器的端口
#指定多个端口映射
docker run -itd -p 8080:80 -p 8081:81 --name mynginx nginx

5.2 网络管理

相关命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 如果多个容器想进行通信,那么这些容器必须要在同一个网络中
$ docker network --help
Usage: docker network COMMAND

Manage networks

Commands:
connect 把一个容器加入到一个网络中
create 创建一个网络
disconnect 将一个容器从网络中移出
inspect 查看网络细节
ls 列出网络
prune 移除所有不用的网络
rm 移除指定网络

$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5854ecbd3fd7 bridge bridge local
25d01b5a58fd host host local
e6ba185fe6c9 none null local

bridge网络模式

独立的网络栈,独立的IP,外部访问需要端口映射

创建bridge网络

1
$ docker network create -d 网络驱动的名字 要创建的网络的名字

自定义网段与网关

1
2
3
	--subnet:	指定子网络的网段
--gateway: 指定网关
$ docker network create -d bridge --subnet 180.18.10.0/24 --gateway 180.18.10.1

在自定义网路中启动容器

1
2
docker run -itd --name test3 --network 自定义网络名字 ubuntu bash
--network: 指定要加入的网络

容器断开/连接网络

1
2
3
4
5
6
#断开网络
docker network disconnect [OPTIONS] 网络名 容器名
-OPTIONS:
-f: 强制执行
#连接网络
docker network connect 网络名 容器名

host网络模式

容器直接使用宿主机的网络栈,不需要端口映射,无网络开销

1
2
$ docker run -itd --name test4 --network host ubuntu bash
--network host

6.Dockerfile

6.1 dockerfile介绍

按照文件的规则构建镜像,告诉Docker怎么一步步做出自己想要的镜像

1
2
3
4
5
6
7
8
9
10
11
12
#构建一个基于ubuntu的docker定制镜像
#基础镜像
FROM ubuntu:latest

#执行命令
RUN mkdir hello
RUN mkdir world
RUN apt update && apt install -y nginx

#声明暴露端口
EXPOSE 80

  • 宿主机创建一个空目录,将上边的dockerfile文件放到里边
  • 在dockerfile对应的目录中执行一个命令,构建新的镜像
1
2
$ docker build -t mynginx:v1.0 dockerfile所在的目录(./)
-t,--tag: 指定构建出的镜像名字和版本

6.2 dockerfile关键字

FROM

1
2
3
4
5
6
7
FROM 镜像名	
FROM 镜像名:TAG
FROM ubuntu:22.04
#FROM必须要出现在第一行(除注释),可以多次FROM
#如果本地和远程仓库都不存在,报错
FROM nginx
FROM redis

MAINTAINER

1
MAINTAINER 维护人员信息

RUN

1
2
3
4
5
#构建镜像时执行的shell命令,如果命令有确认操作,必须加-y
RUN shell命令
RUN apt update && apt install -y nginx
RUN g++ xxx -o out
RUN ["mkdir","/home/test","-p"]

EXPOSE

1
2
3
4
#设置对外开放的端口
#让宿主机和容器开放端口形成一个映射关系,就可以访问了
# docker run -itd -p 8888:80
EXPOSE 80

6.3 dockerfile运行时指令

CMD

1
2
3
4
#容器启动后默认执行的命令
#改命令会被docker run指定的shell命令覆盖
CMD shell命令
CMD ["shell命令","参数1","参数2"]

ENTRYPOINT

1
2
3
4
#与CMD一样
#但是不会被docker run 指定的shell命令覆盖
ENTRYPOINT shell命令
ENTRYPOINT ["shell命令","参数1","参数2"]

6.4 dockerfile文件编辑指令

ADD

1
2
3
4
#将宿主机文件拷贝到镜像目录中
#如果是压缩包则进行解压缩
ADD ["宿主机文件","镜像目录/文件"]
ADD ["./a.txt","/home/test/a.txt"]

COPY

1
2
#与ADD类似,只是不会自动解压
COPY ["./a.tar.gz","/home/"]

VOLUME

1
2
3
4
5
6
7
8
#创建数据卷容器
docker run -itd --name containsVolume -v /volume ubuntu bash
#测试容器挂载数据卷容器
docker run -itd --name test1 --volumes-from containsVolume ubuntu bash


#VOLUME指令可以在镜像中声明挂载,这样只要通过该镜像创建的容器都有了挂载点
VOLUME ["/data"]

6.5 dockerfile环境指令

ENV

1
2
3
4
5
6
7
8
9
#设置环境变量, 可以在RUN之前使用,然后RUN命令时调用
#容器启动时这些环境变量都会被指定
ENV <key> <value>
ENV <key>=<value>
ENV HELLO 12345
ENV HELLO=12345
RUN mkdir /home/a/b/c/d/e/f/.../z
ENV MYPATH=/a/b/c/d/e/.../z
RUN cd /home $MYPATH

WORKDIR

1
2
3
4
5
6
7
8
9
#切换目录,为后续的RUN、CMD、ENTRYPOINT 指令配置工作目录。相当于cd
#可以多次切换
WORKDIR /path/to/work
RUN a.sh
WORKDIR /path
WORKDIR to #相对路径(cd to)
WORKDIR workdir
RUN pwd
/path/to/workdir

7.docker-compose

Compose是Docker容器进行编排的工具,定义和运行多容器应用,可以一条命令启动多个容器,使用Docker Compose不再需要使用shell脚本来启动容器。

Compose通过一个配置文件来管理多个Docker容器,在配置文件中,所有的容器通过services来定义,然后使用docker-compose脚本来启动,停止和重启应用,和应用中的服务以及所有依赖服务的容器,非常适合组合使用多个容器进行开发的场景。

配置文件默认名字: docker-compose.yaml/yml

7.0 yaml文件格式

  • 大小写敏感
  • 使用缩进表示层级关系
  • 不能使用tab建缩进,只能使用空格键
  • 缩进长度没有限制,只要对齐就表示这些元素属于一个层级
  • 字符串可以不用引号标注

7.1 docker-compose配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
version: '3'	#docker-compose 的版本
services: #服务
web: #服务名,自己起的,每个服务名对应一个启动的容器
image: nginx:latest
container_name: myweb
ports: #向外开放的端口
- "8080:80"
- "3000" #3000是容器对外开放的端口,宿主机随即分配一个与3000映射
networks:
- front-tier
- back-tier
enviroment: #环境变量
RACK_ENV: development
SHOW: 'true'
command: tree -L 3
extends:
file: common.yml
service: webapp

redis:
image: redis:latest
links:
- web
newtworks:
- back-tier

lb:
image: dockercloud/haproxy
ports:
- 80:80
networks:
-front-tier
-back-tier
#挂载目录,相当于-v
volumes:
- /var/run/docker/sock:/var/run/docker.sock
depend_on:
- web
- redis
- lb
networks: #声明网络
front-tier:
driver: bridge
back-tier:
driver: bridge

7.2 docker compose 命令

compose 服务启动、关闭、查看

1
2
3
4
5
6
7
8
9
10
11
12
前置条件:docker-compose.ymal
#启动docker容器
$ docker compose up -d
-d: 以守护进程方式启动(后台运行)#不加会占用一个终端,用来输出启动过程中的日志信息
#如果配置文件不叫docker-compose.yaml,叫temp.yaml,则要指定配置文件
$ docker compose -f temp.yaml up -d

#关闭,并删除容器
$ docker compose down

#查看启动的容器
$ docker compose ps

容器开启、关闭、删除

1
2
3
4
5
6
7
8
#启动某一个容器
$ docker compose start 服务名

#容器的关闭,没有删除
$ docker compose stop 服务名

#删除
$ docker compose rm 服务名