2021-06-12 系统化装修 2019-11-27 初稿
惊讶地发现 docker 官网国内访问飞快,可能换CDN了,挺好,当初都打不开。
惯例,依旧是技术卡片:
新技术QA | |
---|---|
技术名称 | Docker |
文档官网 | https://www.docker.com/ |
作者、技术团队 | Docker |
能做解决什么问题 | 环境封装隔离、简单轻量部署 |
特点、优点 | 名气大,插件丰富,社区氛围好 |
同类选型 | 编排docker-swarm/k8s/mesos |
缺点、踩坑注意 | |
宣传语 | |
选型关键词 | docker、容器 |
docker基本上是容器技术的事实标准了。
OCI全称为开放容器标准(Open Container Initiative),它是一个轻量级、开放的治理结构。OCI组织在 Linux 基金会的大力支持下,于 2015 年 6 月份正式注册成立。基金会旨在为用户围绕工业化容器的格式和镜像运行时,制定一个开放的容器标准。目前主要有两个标准文档:容器运行时标准 (runtime spec)和容器镜像标准(image spec)。
似乎是现有了标准,倒推 docker 进行标准改革。后来 docker 公司把 docker 中的 containerd 拆分捐献给社区。撇开历史不谈了。
本文并不是 docker 使用说明书,不会完整介绍 docker ,只会在表面上介绍。目标受众是前端同学日常可使用的技巧。
0 概念
总体回顾时候掌握几个核心:
- 镜像 image,可以类比npm包、系统安装盘
- 容器 container
- 正在运行的镜像+配置,镜像运行的实体
- 可以被创建、运行、暂停、停止、删除
- 仓库 hub
- 类似npm仓库
- 网络 network
- 多容器网络隔离
- 数据卷 volume
- 数据统一存储
关于docker的基础概念,可参考知乎的回答,这里做个引用:
https://www.zhihu.com/question/28300645/answer/67707287
docker把开源项目修改成 moby 了,所以github上搜不到。
1 安装和配置
1.1 安装
再次感叹现在下载速度真快,官网找最新版下载,网速拉满。
1.2 配置加速服务
这个是针对国内的,不知道目前还有没有必要,就是配置国内的镜像地址,方便下载。
- 使用阿里云的加速器加速访问。在阿里云中,每个加速器用户的地址是不一样的。具体的在这里看 https://cr.console.aliyun.com/
- 使用腾讯云服务。参考网址 https://cloud.tencent.com/document/product/1207/45596
具体操作:客户端-设置Preferences - Docker Engine,把下边的json放入:
{
//...
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com"
],
// ...
}
1.3 运行
现在 docker 的控制面板,功能非常全可视化功能很完整,原本我提到 vscode 插件功能很全,现在一对比,官方也不差。
等到docker图标不动了,打开命令行:
docker -v
docker --help
docker常用api一览:
常用命令一览:
docker start 容器名 -d
docker stop 容器名
docker exec -it nginx bash
其他的一般通过 dockerfile 进行配置,后面详细说。
如何构建镜像:
docker commit
基于容器提交为镜像docker build
从 dockerfile 构建镜像
2 DockerHub
2.1 安全性
hub类似npm,放了很多镜像。镜像有的是官方维护的,有的是个人的封装的,就和github 是一样。
如果考虑到个人封装带来的安全隐患,常见的是官方的镜像进行组合配置,托管到第三方平台,比如阿里云、腾讯云,能不能自托管我得看看,类似cnpm私有+共有还得再看看。
docker官方提供了一个镜像 https://hub.docker.com/_/registry,用来创建私有仓库。将这个镜像运行起来,就是一个私有化仓库了,可以接受push
具体如何使用,在 05 | 仓库访问:怎样搭建属于你的私有仓库?中提及了,这里略过。专业级的管理工具使用这个 https://goharbor.io/
2.2 Node 的镜像
hub也可以访问了,挺好。
因为是前端,我们ci/cd 都是基于node来完成的,打开 https://hub.docker.com/_/node,观察打开的页面结构。看到密密麻麻的 tags:
- node:
测试时候用一下,实际中用不到,node运行在一个系统环境上,这个系统自带了常见软件包 - node:
-alpine。实际主要用这个,基于alpine系统,这个系统体积特别小,自带的工具也特别少。 - node:
-slim
一般来说,我们要使用 alpine+node具体版本号,一般不用latest防止不兼容的变更。
比如,对于2021-06-12 来说,node的lts是14.17。所以我推荐这个 14.17.0-alpine3.13
,两遍版本都锁定。这个体积是 39.5M(解压之后会大),见下图
otto@192 ~ % docker pull node:14.17.0-alpine3.13 <-- 这里去下载
14.17.0-alpine3.13: Pulling from library/node
540db60ca938: Pull complete
7cc48f18abe7: Pull complete
d6ae1695c8a1: Pull complete
3f5fc9c643d6: Pull complete
Digest: sha256:782e891986f16cc661bfe928d0d163d4d0e6cf5cc05453dff2093c015fcc4a64
Status: Downloaded newer image for node:14.17.0-alpine3.13
docker.io/library/node:14.17.0-alpine3.13 <-- 安装完成
3 Network
docker的容器网络,非常复杂且重要。
输入 docker network ls
可以看到网络情况
- bridge 默认类型,会为容器分配一个子网ip,通常是
127.17.0.X
- host 容器共享主机网络,直接占用主机端口,不需要 -p 来映射
- 好处是不用配置端口
- 坏处是缺少了网路隔离性
- 一般不用,但是应为可以访问其他容器,可以做代理
- none 不会分配ip,其他容器和主机都不能通过网络访问他,和外界隔离
- 自定义bridge ,截图上是sentry的网络,比如同时存在前端-后端-数据库三个容器,会彼此依赖,如果默认bridge,就不能和其他容器网络隔离
- 这里自定义一个网络,这几个容器在一个网络中,对外界隔离
如何创建网络 docker network create Name
,创建成功会返回id
docker network create [name]
docker network inspect [name|id] 可以查看网络请求
#手动删除网络
docekr network rm [name|id]
# 清除未使用的网络
docker network prune
稍微了解一些了,以前我用 docker设置nginx容器,如何跨容器管理,其实就可以使用 host了
4 容器存储
三种挂载:
- 存储卷。
- 绑定挂载。
- tmpfs挂载。
首先默认的数据会产生在容器内部,如果容器被删除或者无法访问,数据取不出来,所以一般会外置挂载。
docker本身提供 存储卷,私有格式,只能被docker修改。docker能跨平台读取,容易备份迁移。
比如,如果容器依赖的卷不存在会自动创建,对卷本身可设置属性docker volume
感觉就是个私有格式,容易操作
绑定挂载。直接挂载主机文件或者目录。可以随意修改。比如配置文件、源码、编译后代码
tmpfs。主机内存中,不写入文件,不想持久化的数据、快速大量读写的数据。
5 Dockerfile
5.1 说明
dockerfile 是配置文件,是实际工作中非常重要的一个概念。里面定义了docker镜像的封装。
属性 | 解释 |
---|---|
from | 第一行,基于哪个镜像 |
run | 跟一个具体的命令 |
add | 拷贝本机、远程文件到镜像内部 |
copy | 拷贝本机文件到镜像内部 |
user | 指定容器启动的用户 |
entrypoint | 容器的启动命令 |
cmd | 给entrypoint指令提供默认参数,也可以单独使用cmd指定容器启动参数 |
env | 指定环境变量 |
arg | 外部变量,可被env覆盖 |
expose | 指定容器监听端口 |
workdir | 设置镜像内的basePath |
volume | 挂载 |
注:
run
命令尽量一行写完,也就是a命令 && b命令
,否则构建时候会创建不同的层。add
vscopy
,推荐copy,功能更简单。add支持远程,压缩包会自动解压- cmd vs entrypoint,前者启动容器,后者容器初始化,语义不同
- 多个cmd 只有最后一个生效
- entrypoint 是容器初始化,一般外挂脚本
- https://yeasy.gitbooks.io/docker_practice/
5.2 最佳实践
- 务必创建
.dockerignore
文件。 - 容器只运行一个应用,多容器使用 compose
- 以为run分层,RUN及时合并
- 指定images标签,保持一致
- RUN之后删除无关文件。比如
apt-get update
之后,删除/var/lib/apt/lists/
目录。 - 镜像尽量使用 alipine
- 合理调整copy和run顺序
不要每次都安装npm。
先COPY package.json /app
。
在RUN npm install
在COPY . /app
run时候 RUN npm config set registry xxx && npm i
5.3 .dockerignore
.git
node_module
隔离。
5.4 构建
docker build -t [imageName]:[tag] .
#最后有个点,用来指定构建过程的上下文环境的目录。
6 docker-compose
本质是一套脚本,通过读取 compose 配置文件,生成多个容器,统一编排。
线上单机部署也可以使用 docker-compose,但是 docker-compose 无法做到集群调度,想要把多台服务组成容器集群,推荐使用 kubernetes
docker-compose up -d
docker-compose down
docker-compose logs nginx
7 实战
7.1 案例: Mysql+wordpress
version: '3'
services:
mysql:
image: mysql:5.7
volumes:
- mysql_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: mywordpress
MYSQL_USER: mywordpress
MYSQL_PASSWORD: mywordpress
wordpress:
depends_on:
- mysql
image: wordpress:php7.4
ports:
- "8080:80"
restart: always
environment:
WORDPRESS_DB_HOST: mysql:3306
WORDPRESS_DB_USER: mywordpress
WORDPRESS_DB_PASSWORD: mywordpress
WORDPRESS_DB_NAME: mywordpress
volumes:
mysql_data: {}
如何生成docker镜像,要么dockerfile 逐层构建,或者操作之后统一commit,推荐第一种
7.2 案例:Node工程
假设我们有一个 npm 项目。
# 使用官方 Node.js 12 轻量级镜像.
# https://hub.docker.com/_/node
FROM node:14.17-alpine3.11
# 定义工作目录
WORKDIR /usr/src/app
EXPOSE 8080
# 将依赖定义文件拷贝到工作目录下
COPY package*.json ./
copy *.lock ./
# 以 production 形式安装依赖
RUN npm install --only=production
# 将本地代码复制到工作目录内
COPY . ./
# 启动服务
CMD [ "npm","run", "start" ]
// .dockerignore
node_modules
这里为了避免缓存失效,把不常变动的操作放到前面。
docker build . -t name:tagName
docker run -it -d -p 8080:8080 --name xx