更好的阅览体验请移步至:zhengxiaoping.xyz/fullstack/D…

本文适用于第一次入门Docker的新手,假如你开端注意到Docker,恭喜你!你将成为一个美好的人。因为在学完Docker后,相信你会跟我一样,感叹与Docker的相识简直是 相见恨晚!

假如告诉你,能够用 一行指令将nginx运转起来,你会不会感到惊奇?

假如告诉你,还是 一行指令,不仅将nginx运转起来,而且将你的网站运转在其间 ,你是否会感到惊奇?

先不要惊奇。让咱们现在就开端动手,将上面不可思议的工作变成现实!

装置Docker

在开端学习Docker常识前,先花几分钟的时刻装置Docker。引荐以Windows作为入门Docker的渠道,因为Windows版的Docker Desktop有很良好的界面,对于新手而言十分友好。

下载链接:www.docker.com/

听说很少有人将Docker讲懂?我来试试!

其他系统的装置也是十分简略、快速的,参考官网的装置文档即可。

开胃菜:在Docker上跑一个服务器

首要,咱们在本地D盘的hello-docker目录,新建一个index.html文件,内容如下:

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Hello</title>
</head>
<body>
  Hello, Docker!
</body>
</html>

然后,翻开控制台,运转一行指令:

docker run -d -p 80:80 -v d:/hello-docker:/usr/share/nginx/html nginx:latest

紧接着,咱们翻开 http://localhost/ ,奇妙的工作产生了:

听说很少有人将Docker讲懂?我来试试!

整个进程不到1分钟,咱们现已将开发的内容布置到nginx服务器上了!!

是的,这便是Docker。事实上,运用Docker,你只需求输入一行指令,就能够将一个整合了多个服务器及各种中间件的庞大系统运转起来。更为美妙的是,当你为你的服务替换主机时,依然只需求一行指令,就搞定一切工作。

了解Docker

前面咱们经过一行指令成功把一个静态web网页布置到了nginx上,对于运用者而言会十分猎奇,Docker到底是怎么做到这一切的呢?

事实上, 你的软件怎么合作运转是确认的 ,例如一个简略的博客系统,至少由以下三个部分构成:

  • 数据库(存储数据)
  • 运用服务器(供给运用接口)
  • web静态服务器(前端运用布置)

为了让你的博客运用跑起来,你或许需求这些进程:

  1. 装置mysql,设置用户名与密码,并运转
  2. 运转一个node服务器(如express或koa),衔接mysql,这个进程需求指定主机名、端口、用户名、密码等信息
  3. 运转一个nginx服务器,将开发的代码布置在其上,此进程根据需求或许需求修正nginx的装备文件

你会发现,不论你换多少台主机进行布置,你总是要重复上面的进程,而这些进程只是在第一次考虑它时具有价值,后续的一切劳作都是冗余的、无意义的。

Docker便是来 办理这些进程 的,正因为系统需求哪些配件以及各部分怎么合作运转是确认的,因而,能够将这些制造为一个标准的流程,由Docker去办理。

正如它的姓名(Dock:船坞),Docker是一个码头工人,担任搬运你的货品(运用),将你的工作中最为枯燥、无意义的一部分完全接收。

长话短说,你能够认为:

有了Docker,你再也不需求亲力亲为去装置和装备那些复杂的软件,软件供应商会将自己的软件以及它的运转环境打包好,你只要叮咛Docker将它们搬过来,然后按一下开机键,就能够运转了。

了解镜像与容器的联系

前面的叙说涉及到Docker最中心的两个概念:软件供应商打包好的可运转的货品,称为 镜像 ,而你运转的,称为 容器 。(注意,镜像与容器并不是一对一的联系,这里的叙说并不准确,详情请继续阅览)

假如你是一个有面向目标开发经验的开发者,了解镜像与容器的联系十分简略,镜像便是类,容器便是目标(或实例)。

假如你不是,那么你能够简略了解这些联系:

  • 镜像 = 菜谱。 例如nginx镜像就如鱼香茄子的菜谱,具体说明了鱼香茄子的制造进程(调料、原料、锅、火候等);
  • Docker = 厨师。 Docker从码头工人摇身一变成为米其林大厨,它担任依照菜谱的要求准备资料并烹饪你的美食;
  • 容器 = 菜。 当Docker这个“大厨”完成烹饪后,你就取得了一份鱼香茄子。

因而,你能够让Docker炒5份鱼香茄子(一个镜像运转多个容器,结构集群环境),同一份菜,或许有多个菜谱,或许有的菜谱做出的鱼香茄子会有一些地方特色,例如广东的鱼香茄子会加入沙茶酱(同一类镜像或许有多个版别,有一些会供给一些已有装备或高档特性,例如nginx的官方镜像和其他厂商实现的镜像)。

同时,不同的菜,菜谱的厚度是不同的,西红柿炒蛋或许1页就够,可是满汉全席或许需求一本书(不同镜像的大小是纷歧的,能够简略认为镜像要做的工作越多越杂,镜像就越大)。

怎么将一个容器跑起来?

还是以菜谱、厨师与菜的联系来了解,首要:

第一步:你得有个厨师(装置Docker)

第二步:要根据你的需求,获取你的菜谱,这个进程被称为拉取镜像。

例如你想取得一个nginx镜像,只需求运用这个指令即可:

docker pull nginx:latest
# 或:
# docker image pull nginx:latest

你能够运用 docker image ls 或直接在Docker Desktop中查看刚刚拉取的镜像:

听说很少有人将Docker讲懂?我来试试!

第三步:叮咛厨师,做菜!(运转镜像,容器化/实例化)

docker run -d -p 80:80 nginx:latest

最终,翻开 http://localhost ,就能够食用你的美食了!

制造自己的“菜谱”

前面咱们说过,镜像是菜谱,Docker是厨师,容器是菜,那咱们能不能让Docker在做菜的时候放点其他调料呢?不能。厨师会忠实地依照菜谱做菜,并不会改造菜谱。那怎么做一份定制的鱼香茄子呢?你需求履行以下进程:

  1. 依照鱼香茄子的菜谱,制造一份自己的菜谱(例如在出锅前放一勺糖);
  2. 叮咛厨师,依照自己的菜谱做菜,做出契合自己口味的鱼香茄子。

这个制造定制菜谱的进程便是 镜像制造

镜像制造需求的中心元素便是 Dockerfile,相信你曾经不止一次看到过它,它便是“菜谱”,用来描绘你定制的这道菜的制造进程。让咱们来看一个简略的比如:

FROM nginx:latest
COPY . /usr/share/nginx/html
  • FROM nginx:latest 根据nginx镜像制造新的镜像,比如根据鱼香茄子的菜谱制造自己的鱼香茄子菜谱
  • COPY . /usr/share/nginx/html 将目录内容拷贝到nginx的入口目录,这样未来运转nginx时,就能跑起自己的项目了

接下来,你需求开端制造镜像:

docker build -t mynginx:latest .

不如?现在就来运转一个博客?

首要,咱们需求运转一个数据库来存储咱们博客的数据,不如就mysql吧。翻开指令行运转指令:

docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=blog mysql:latest

指令详解:

  • -d 后台运转
  • -p 3306:3306 露出端口,将内部3306端口映射到本机3306端口(假如本机存在mysql并已运转,则会产生端口占用报错)
  • -e MYSQL_ROOT_PASSWORD=root 设置mysql的root用户密码为 root
  • -e MYSQL_DATABASE=blog 设置mysql默认数据库,这里设置为blog,会主动创立
  • mysql:latest 运用mysql的latest版别作为镜像

mysql容器运转后,你能够经过例如Navicat等数据库客户端衔接,因为它的端口现已露出到了本机。

接下来,咱们来运转一个node服务器并衔接mysql。

咱们选择koa作为结构,首要,装置依靠:

pnpm i koa mysql2
# yarn add koa mysql2
# npm i koa mysql2

db.js

const mysql = require('mysql2')
const { MYSQL_HOST } = require('./config')
let pool
exports.createPool = function() {
  pool = mysql.createPool({
    host: MYSQL_HOST,
    port: '3306',
    user: 'root',
    password: 'xpzheng',
    database: 'hello',
    charset: 'utf8mb4',
  })
  return pool
}
exports.init = function() {
  return new Promise((resolve, reject) => {
    pool.getConnection((err, conn) => {
      if (err) return console.error(err)
      conn.execute('drop table if exists t_blog;', (err) => {
        if (err) return reject(err)
        conn.execute(`create table t_blog (
          title varchar(255),
          text text
        );`, (err2) => {
          if (err2) return reject(err2)
          resolve()
        })
      })
    })
  })
}

index.js

const Koa = require('koa')
const cors = require('@koa/cors')
const Router = require('@koa/router')
const { createPool, init } = require('./db')
const app = new Koa()
const router = new Router()
let db
function query(sql) {
  return new Promise((resolve, reject) => {
    db.query(sql, (err, results) => {
      if (err) return reject(err)
      resolve(results)
    })
  })
}
function execute(sql) {
  return new Promise((resolve, reject) => {
    db.getConnection((err, conn) => {
      if (err) return reject(err)
      conn.execute(sql, err2 => {
        if (err2) return reject(err2)
        resolve()
      })
    })
  })
}
router.get('/', ctx => {
  ctx.redirect('hello')
})
router.get('/hello', ctx => {
  ctx.body = 'Hello, Koa!'
})
router.get('/blog/add', async(ctx) => {
  if (!ctx.query.title || !ctx.query.text) {
    ctx.body = '请传入标题与内容'
    return
  }
  await execute(`
    insert into t_blog (title, text) values ('${ctx.query.title}', '${ctx.query.text}')
  `)
  ctx.body = true
})
router.get('/blog/list', async(ctx) => {
  const result = await query(`select * from t_blog`)
  ctx.body = result
})
app
  .use(cors())
  .use(router.routes())
  .use(router.allowedMethods())
  .use(async(ctx, next) => {
    next()
  })
;(async function() {
  try {
    db = createPool()
    await init();
  } catch (err) {
    console.error(err)
  }
  app.listen(3000)
})()

db.js 中,咱们衔接了msyql并创立了 t_blog 表。index.js 文件中,咱们供给了一个增加文章与查询文章列表的接口。

接下来,咱们再创立一个vite项目,访问这个node服务,增加或获取文章数据。

最终,将该项目布置在nginx中,访问作用如下:

听说很少有人将Docker讲懂?我来试试!

至此,咱们将整个博客运用搭建并布置成功了!

具体代码请参考:github.com/shoppingzh/…

Docker学习道路

以下引荐了一个较为合理的Docker学习道路,不论你选择的道路是什么,还是引荐从官方文档下手。

  • 装置Docker
  • 了解镜像与容器的联系
  • 运用官方镜像,在Docker上跑一个服务器
  • 自己制造一个镜像
  • 常用Docker指令
  • 制造自己的镜像,跑一个简略的运用
  • 进一步学习:知道网络与卷
  • 多容器布置面临的窘境
  • 知道Docker Compose
  • Docker常识系统
  • 分布式布置
  • 未完待续…

常用指令

镜像

列出一切镜像

docker image ls

删去镜像

docker image rm nginx:latest

制造镜像

docker build -t myimage:1.0 . -f /xxx/yyy/Dockerfile

容器

运转容器

docker run -d -p 80:80 --mount source=nginx,target=/usr/share/nginx/html nginx:latest
  • -d 后台运转
  • -p 露出端口
  • --mount 挂载卷

中止运转容器

docker stop 5f79d10d97

5f79d10d97 表明容器运转的仅有标识。

列出正在运转的镜像

docker container ls

听说很少有人将Docker讲懂?我来试试!

删去容器

docker container rm 5f79d10d97

创立卷

docker volume create nginx

列出一切卷

docker volume ls

听说很少有人将Docker讲懂?我来试试!

运转时绑定卷

办法1:指定卷名(需求先创立卷,假如没创立,docker会主动创立)

docker run -d -p 80:80 --mount source=my-volume,target=/usr/share/nginx/html nginx:latest

办法2:自行指定目录(更灵活)

docker run -d -p 80:80 --mount type=bind,src=d:/nginx,target=/usr/share/nginx/html nginx:latest

删去指定卷

docker volumn rm nginx

网络

列出一切网络

docker network ls