logo科技微讯

如何把 GatsbyJS 网站通过 docker 部署到云服务器

作者:科技微讯
日期:2019-10-21
📜 文章

为什么要通过 Docker 部署

Gatsbyjs 是一个静态网站生成器,用它搭建的网站由一个个静态文件组成,可以直接部署在 github pages 等静态网站托管服务,这样是免费的,但出于 SEO,访问速度,自由度等方面的考虑,我还是部署到自己的服务器吧,虽然麻烦了一点,而且我刚好有一个腾讯云服务器,新用户购买也不贵,我买了三年,不想放着浪费了。

因为一个服务器可以运行 N 多个程序,每个程序所依赖的环境可能都不一样,这些环境可能互相影响呢,而且万一哪天我不爽要重装系统,那我不仅要备份程序代码,还要记住我之前折腾过的所有配置/安装过的所有依赖等等,重装系统之后要从头搭建,很烦。

所以我打算把我的 gatsby 网站 docker 化,docker 化后的网站可以比喻为一个压缩包,把这个压缩包 push 到 docker hub,重装系统后把这个压缩包 pull 下来就能马上运行,无需从头配置。如果哪天我把腾讯云换成其他云,同样只要 pull 下来就能使用,非常方便。

前提

  • 在你的本地电脑和云服务器安装 docker,不同系统有不同的安装方法,可参考 docker 官方的安装说明
  • 了解基本的 docker 概念,基本的命令行,可参考 docker 的 quick start
  • 创建一个 gatsbyjs 网站,如果你还没有,可以用 gatsbyjs 的各种 starter,例如执行 gatsby new blog https://github.com/gatsbyjs/gatsby-starter-blog 会创建一个 blog 文件夹,里面就是一个完整 gatsby 网站的代码;

第一步: 定义 dockerfile 并运行 image

Gatsbyjs 官方提供了一个 gatsby docker image,其 github 主页有使用说明,不过 docker 新手可能看不懂,所以才有了这篇文章。

在你的本地电脑,通过命令行工具进入 blog 文件夹,npm i 之后运行 gatsby build,得到 /public 文件夹,这个文件夹就是网站的静态文件。

接着新建一个命名为 Dockerfile 的文件,在这个文件添加以下代码:

FROM gatsbyjs/gatsby:onbuild

gatsby 官方 docker image 有两个 tag,分别是 onbuild 和 latest,onbuild 取自 ONBUILD 这个 dockerfile 命令,两个 tag 的区别就是 onbuild 多了 ONBUILD ADD public/ /pub 这行代码,所以你也可以把上述代码改成:

FROM gatsbyjs/gatsby:latest
ADD public/ /pub

接着根据这个 Dockerfile 创建 image,在命令行工具执行:

docker build -t kejiweixun.com:latest .

-t 表示 tag,即标签,我打了 latest 这个标签,注意最后的 . 不能省略,表示基于 Dockerfile 所在的目录创建 image,kejiweixun.com 是所创建的 image 的名称,你可以自定义。

接着运行这个 image:

docker run --rm -p 80:80 kejiweixun.com

image 运行之后就创建了一个 container,--rm 的作用是当这个 container 被停止后,自动清除 container,如果没有 --rm,container 被停止后会被保留。-p 的作用是把电脑的端口和 container 的端口进行映射,第一个 80 是电脑的端口,这意味着你可以在浏览器通过 localhost:80 访问这个 container,第二个端口之所以也是 80,是因为官方的 image 暴露的就是 80 端口,所以你通过本地电脑的 80 端口访问 container,其实就是访问 container 暴露的 80 端口。

最后打开浏览器,前往 localhost 这个网址就可以访问网站,这时命令行工具会实时显示 log,如果你不希望显示这些 log,可以添加 -d 选项:

docker run --rm -d -p 80:80 kejiweixun.com

第二步: 对 image 进行配置

gatsby 官方的 docker image 其实封装了一个叫 alpine 的 linux 系统,alpine 体积大概只有 5MB,比 Ubuntu 等 linux 系统小得多,所以通过上述方法生成的 image 体积只有 15MB。官方 image 还在这个 alpine 系统中安装了 nginx 服务器,网站的静态文件就是通过 nginx 提供给访客的。

nginx 功能强大,我们可以通过更改 nginx 的配置文件改变 nginx 的功能,gatsby 的官方 image 提供了更改配置文件的方法,方法一是在定义 Dockerfile 的时候附加配置文件,方法二是给 docker run 添加 -e 选项。例如:

docker run --rm -d -e CACHE_IGNORE=html -p 80:80 kejiweixun.com

文档显示 -e CACHE_IGNORE=html 这个选项表示 nginx 在提供 html 文件时,把 header 的 Cache-Control 值设置为 no-store,当然这是本来就是默认配置,所以和前面的 docker run 命令没有区别。但 gatsby 官方文档建议 page-data.jsonsw.js 文件也不应该被缓存,为了不缓存 json 文件,所以把刚才的命令改为:

docker run --rm -d -e CACHE_IGNORE=html|json -p 80:80 kejiweixun.com

但为了不缓存 sw.js 文件,恐怕要通过前面提到的第一种方法实现,即在定义 Dockerfile 的时候附加配置文件,具体怎么配置,可参考 nginx-boot.sh 这个文件,以及官方说明

第三步: 使用 docker-compose 运行 image

如果你要更改的 nginx 配置有很多,那 docker run 这条命令可能很长,例如:

docker run --rm -d -e CACHE_IGNORE=html -e CACHE_IGNORE=html -e CACHE_IGNORE=html -e CACHE_IGNORE=html -e CACHE_IGNORE=html -e CACHE_IGNORE=html -e CACHE_IGNORE=html -e CACHE_IGNORE=html -p 80:80 kejiweixun.com

每次运行 image 都要输入这么长的命令,是不是很烦? 有两种解决方法,第一种是把 -e 改为 --env-file,把所有环境变量选项写在一个文件中执行,另一种方法是通过 docker-compose up 运行 image,而不是通过 docker run 运行。如果只是为了解决命令行太长的问题,那这两个方法都差不多,但 docker-compose 还有很多其他作用,是一个非常值得学习的知识点,所以这里说说怎么用 docker-compose。

首先要安装 docker-compose,方法请查阅官方文档,不过如果你的 mac 或 win 电脑是通过 Docker Desktop 安装 docker 的话,那不需要再单独安装 docker-compose,因为 Docker Desktop 自带了 docker-compose,如果你的服务器是 linix 系统,那通常要单独安装 docker-compose。

安装完 docker-compose 之后,在 blog 文件夹创建一个名为 docker-compose.yml 的文件,并在里面添加如下代码:

version: "3.7"
services:
  kejiweixun.com:
    image: kejiweixun.com
    environment:
      - CACHE_IGNORE=html|json
    ports:
      - "80:80"

docker run --rm -d -e CACHE_IGNORE=html|json -p 80:80 kejiweixun.com 比一比,简直一模一样。区别是 services 下多了一行 kejiweixun.com,这一行是 image 运行后 container 的名称。把一长串的命令记在一个文件中,以后再使用就简单很多了。不过 docker-compose 其实并不十分适合于 production 阶段,更适合用于 development 阶段,生产阶段可以用 docker swarm。

接着执行:

docker-compose up -d

这样 image 就运行起来了,不需要指定 docker-compose.yml 这个文件,它会自动找到同目录下的文件。要想停止这个 container 只要执行:

docker-compose down

同样不用指定文件,它会自动停止 container,并自动清除这个 container,作为对比 docker run 还要加 --rm 才能自动清除。

docker-compose 另一个显著优点是更新 container 更方便。例如你更新了网站代码,通过 gatsby build 生成了新的静态文件,然后通过 docker build 创建了新的 image,如果你是通过 docker run --rm 运行 image 的话,你需要先通过 docker container stop 停止这个 container,这段时间用户无法访问你的网站,最后通过 docker run 运行新的 image。

但如果你用 docker-compose,你不需要先停止原来的 container,准备好新的 image 之后,直接通过 docker-compose up -d kejiweixun.com 就可以让 container 基于新的 image 运行,注意 kejiweixun.com 指的是 container 的名称,即 yml 文件中 service 下那一项定义的名称,不是 image 的名称,虽然这里 image 的名称也是 kejiweixun.com。

docker-compose 还可以同时 up 多个 image,同时 down 多个 image,很好用。

第四步: 部署到云服务器

通常以上操作都在本地电脑进行,确认没有问题之后,把你创建的 image 上传到 docker hub,不过要先把本地的 image 关联到 docker hub 的 image:

docker tag kejiweixun.com:latest kejiweixun/kejiweixun.com:latest

kejiweixun/kejiweixun.com:latest 前面的 kejiweixun 是你的 docker hub 用户名,后面的 kejiweixun.com 是位于 docker hub 的一个叫 kejiweixun.com 的仓库,你可以自定义,不一定要和本地的 image 名称一致,但我为了方便写成一样了。

然后通过下面的命令把 image 上传到 docker hub,如果这是你第一次 push,可能会提示你先登录,按要求操作即可。

docker push kejiweixun/kejiweixun.com

接着登录你的云服务器,按照前文所说的方法在服务器端安装 docker 和 docker-compose,最后在服务器执行:

docker run --rm -d -e CACHE_IGNORE=html|json -p 80:80 kejiweixun/kejiweixun.com

如果服务器本地没有 kejiweixun/kejiweixun.com 这个 image,它会自动从 docker hub 寻找并自动下载下来。

当然也可以用 docker-compose,但你需要先把刚才创建的 docker-compose.yml 文件上传到服务器,或者直接在服务器创建 docker-compose.yml 文件,然后:

docker-compose up -d

这时在浏览器输入你的服务器 ip 地址,应该就可以访问你的网站了,如果你的服务器已经绑定了域名,那应该也可以通过域名访问。

结论

通过 gatsbyjs 官方提供的 docker image 可以方便地把自己搭建的 gatsby 网站通过 docker 的方式部署到自己的服务器中,例如腾讯云等等。部署完成之后,你可能还要添加 ssl,让网站可以通过 https 访问,但这不是这篇文章讨论的范围啦。

donation赞赏
thumbsup0
thumbsdown0
暂无评论