跳到主要内容

如何在 Digital Ocean 上部署 Deno

Digital Ocean 是一家流行的云基础设施提供商,提供各种托管服务,从网络、计算到存储不等。

以下是一步一步的指南,使用 Docker 和 GitHub Actions 部署 Deno 应用到 Digital Ocean。

首先需要满足以下前提条件:

创建 Dockerfile 和 docker-compose.yml 文件

为了专注于部署,我们的应用将仅包含一个 main.ts 文件,返回一个字符串作为 HTTP 响应:

import { Application } from "https://deno.land/x/oak/mod.ts";

const app = new Application();

app.use((ctx) => {
ctx.response.body = "Hello from Deno and Digital Ocean!";
});

await app.listen({ port: 8000 });

然后,我们将创建两个文件 — Dockerfiledocker-compose.yml,用于构建 Docker 镜像。

在我们的 Dockerfile 中,添加以下内容:

FROM denoland/deno

EXPOSE 8000

WORKDIR /app

ADD . /app

RUN deno cache main.ts

CMD ["run", "--allow-net", "main.ts"]

接着,在我们的 docker-compose.yml 文件中:

version: '3'

services:
web:
build: .
container_name: deno-container
image: deno-image
ports:
- "8000:8000"

可以通过运行以下命令在本地测试:docker compose -f docker-compose.yml build,然后 docker compose up,并访问 localhost:8000

Hello from localhost

它运行正常!

构建、标记和推送 Docker 镜像到 Digital Ocean 容器注册表

Digital Ocean 有自己的私有容器注册表,我们可以使用它来推送和拉取 Docker 镜像。为了使用该注册表,让我们首先在命令行上安装和认证 doctl

之后,我们将创建一个名为 deno-on-digital-ocean 的新私有注册表:

doctl registry create deno-on-digital-ocean

使用我们的 Dockerfile 和 docker-compose.yml,我们将构建一个新的镜像,标记它,然后将其推送到注册表。注意,docker-compose.yml 将本地构建的镜像命名为 deno-image

docker compose -f docker-compose.yml build

让我们使用标签(tag)将其标记为 new

docker tag deno-image registry.digitalocean.com/deno-on-digital-ocean/deno-image:new

现在我们可以将其推送到注册表:

docker push registry.digitalocean.com/deno-on-digital-ocean/deno-image:new

您应该在Digital Ocean 容器注册表中看到带有 new 标签的新 deno-image

New deno image on Digital Ocean container registry

完美!

通过 SSH 部署到 Digital Ocean

一旦我们的 deno-image 存储在注册表中,我们可以在任何地方使用 docker run 来运行它。在这种情况下,我们将在Digital Ocean Droplet上运行它,这是他们托管的虚拟机。

您的 Droplet 页面上,点击您的 Droplet,然后点击 console 以 SSH 进入虚拟机。您也可以直接从命令行中使用 SSH 连接

为了下载 deno-image 镜像并运行它,运行以下命令:

docker run -d --restart always -it -p 8000:8000 --name deno-image registry.digitalocean.com/deno-on-digital-ocean/deno-image:new

使用浏览器访问 Digital Ocean 地址,现在您会看到:

Hello from Deno and Digital Ocean

成功!

通过 GitHub Actions 自动化部署

让我们使用 GitHub Actions 自动化整个流程。

首先,让我们获取登录 doctl 和 SSH 到 Droplet 所需的所有环境变量:

  • DIGITALOCEAN_ACCESS_TOKEN
  • DIGITALOCEAN_HOST(您的 Droplet 的 IP 地址)
  • DIGITALOCEAN_USERNAME(默认是 root
  • DIGITALOCEAN_SSHKEY(后面会详细说明)

生成 DIGITALOCEAN_SSHKEY

DIGITALOCEAN_SSHKEY 是一个私钥,其公共部分存在于虚拟机的 ~/.ssh/authorized_keys 文件中。

首先,在本地机器上运行 ssh-keygen 命令:

ssh-keygen

在提示输入电子邮件时,确保使用您的 GitHub 电子邮件,以便 GitHub Actions 正确进行身份验证。最后的输出应如下所示:

Output
Your identification has been saved in /your_home/.ssh/id_rsa
Your public key has been saved in /your_home/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:/hk7MJ5n5aiqdfTV

UZr+2Qt+qCiS7BIm5Iv0dxrc3ks user@host
The key's randomart image is:
+---[RSA 3072]----+
| .|
| + |
| + |
| . o . |
|o S . o |
| + o. .oo. .. .o|
|o = oooooEo+ ...o|
|.. o *o+=.*+o....|
| =+=ooB=o.... |
+----[SHA256]-----+

接下来,我们需要将新生成的公钥上传到您的 Droplet。您可以使用 ssh-copy-id 或手动复制,然后 SSH 到 Droplet,并将其粘贴到 ~/.ssh/authorized_keys

使用 ssh-copy-id

ssh-copy-id {{ username }}@{{ host }}

该命令将提示您输入密码。请注意,这将自动从本地机器复制 id_rsa.pub 密钥,并将其粘贴到您的 Droplet 的 ~/.ssh/authorized_keys 文件中。如果您的密钥名称不是 id_rsa,您可以使用 -i 标志将其传递给命令:

ssh-copy-id -i ~/.ssh/mykey {{ username }}@{{ host }}

要测试是否成功:

ssh -i ~/.ssh/mykey {{ username }}@{{ host }}

太棒了!

定义 yml 文件

最后一步是将所有这些放在一起。基本上,我们正在将手动部署的每个步骤添加到 GitHub Actions 工作流的 yml 文件中:

name: Deploy to Digital Ocean

on:
push:
branches:
- main

env:
REGISTRY: "registry.digitalocean.com/deno-on-digital-ocean"
IMAGE_NAME: "deno-image"

jobs:
build_and_push:
name: Build, Push, and Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v2

- name: Set $TAG from shortened sha
run: echo "TAG=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV

- name: Build container image
run: docker compose -f docker-compose.yml build

- name: Tag container image
run: docker tag ${{ env.IMAGE_NAME }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TAG }}

- name: Install `doctl`
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

- name: Log in to Digital Ocean Container Registry
run: doctl registry login --expiry-seconds 600

- name: Push image to Digital Ocean Container Registry
run: docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TAG }}

- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DIGITALOCEAN_HOST }}
username: ${{ secrets.DIGITALOCEAN_USERNAME }}
key: ${{ secrets.DIGITALOCEAN_SSHKEY }}
script: |
# 登录到 Digital Ocean Container Registry
docker login -u ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} -p ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} registry.digitalocean.com
# 停止并删除正在运行的镜像。
docker stop ${{ env.IMAGE_NAME }}
docker rm ${{ env.IMAGE_NAME }}
# 从新镜像运行新容器
docker run -d --restart always -it -p 8000:8000 --name ${{ env.IMAGE_NAME }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TAG }}

当您推送到 GitHub 时,将自动检测到此 yml 文件,并触发部署操作。