Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web): dockerize web application #33

Merged
merged 1 commit into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 61 additions & 2 deletions .github/workflows/build_web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ jobs:
workflow: deploy-web-nightly
token: ${{ steps.app-token.outputs.token }}

build-docker-image:
name: Build and push Docker image

# TODO: Remove after migrating to Cloud Run.
build-docker-image-legacy:
name: Build and push Docker image (Legacy)
runs-on: ubuntu-latest
needs: [release-nightly]
if: ${{ github.event.inputs.name != 'blank' || github.event.inputs.new_tag != 'blank' }}
Expand Down Expand Up @@ -158,6 +160,63 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max

build-docker-image:
name: Build and push Docker image
runs-on: ubuntu-latest
needs: [release-nightly]
if: ${{ github.event.inputs.name != 'blank' || github.event.inputs.new_tag != 'blank' }}
env:
IMAGE_NAME: reearth/reearth-classic-web
defaults:
run:
working-directory: server
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Get options
id: options
env:
TAG: ${{ github.event.inputs.new_tag_short && github.event.inputs.new_tag_short != 'blank' && github.event.inputs.new_tag_short || '' }}
NAME: ${{ github.event.inputs.name }}
SHA: ${{ github.event.inputs.sha_short }}
run: |
if [[ -n $TAG ]]; then
PLATFORMS=linux/amd64,linux/arm64
VERSION=$TAG
TAGS=$IMAGE_NAME:$TAG
if [[ ! $TAG =~ '-' ]]; then
TAGS+=,${IMAGE_NAME}:${TAG%.*}
TAGS+=,${IMAGE_NAME}:${TAG%%.*}
TAGS+=,${IMAGE_NAME}:latest
fi
else
PLATFORMS=linux/amd64
VERSION=$SHA
TAGS=$IMAGE_NAME:$NAME
fi
echo "::set-output name=platforms::$PLATFORMS"
echo "::set-output name=version::$VERSION"
echo "::set-output name=tags::$TAGS"
- name: Build and push docker image
uses: docker/build-push-action@v5
with:
context: web
platforms: ${{ steps.options.outputs.platforms }}
push: true
build-args: VERSION=${{ steps.options.outputs.version }}
tags: ${{ steps.options.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max

release:
name: Release
runs-on: ubuntu-latest
Expand Down
65 changes: 62 additions & 3 deletions .github/workflows/ci_docker_build_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ on:
description: "sha"
required: true
jobs:
build-docker-image:
name: Build and push Docker image
server:
name: Build and push server Docker image
runs-on: ubuntu-latest
if: github.event.inputs.name || github.event.inputs.new_tag
env:
Expand Down Expand Up @@ -63,6 +63,8 @@ jobs:
echo "::set-output name=platforms::$PLATFORMS"
echo "::set-output name=version::$VERSION"
echo "::set-output name=tags::$TAGS"

# TODO: Remove later after migrating to Cloud Run
- name: Fetch reearth-web release
uses: dsaltares/fetch-gh-release-asset@master
with:
Expand All @@ -73,6 +75,7 @@ jobs:
target: server/reearth-web.tar.gz
- name: Extract reearth/web
run: tar -xvf reearth-web.tar.gz; mv reearth-web web; ls

- name: Build and push docker image
uses: docker/build-push-action@v2
with:
Expand All @@ -82,4 +85,60 @@ jobs:
build-args: VERSION=${{ steps.options.outputs.version }}
tags: ${{ steps.options.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
cache-to: type=gha,mode=max

web:
name: Build and push web Docker image
runs-on: ubuntu-latest
if: github.event.inputs.name || github.event.inputs.new_tag
env:
IMAGE_NAME: reearth/reearth-classic-web
defaults:
run:
working-directory: web
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Get options
id: options
env:
TAG: ${{ github.event.inputs.new_tag_short }}
NAME: ${{ github.event.inputs.name }}
SHA: ${{ github.event.inputs.sha_short }}
run: |
if [[ -n $TAG ]]; then
PLATFORMS=linux/amd64,linux/arm64
VERSION=$TAG
TAGS=$IMAGE_NAME:$TAG
if [[ ! $TAG =~ '-' ]]; then
TAGS+=,${IMAGE_NAME}:${TAG%.*}
TAGS+=,${IMAGE_NAME}:${TAG%%.*}
TAGS+=,${IMAGE_NAME}:latest
fi
else
PLATFORMS=linux/amd64
VERSION=$SHA
TAGS=$IMAGE_NAME:$NAME
fi
echo "::set-output name=platforms::$PLATFORMS"
echo "::set-output name=version::$VERSION"
echo "::set-output name=tags::$TAGS"
- name: Build and push docker image
uses: docker/build-push-action@v5
with:
context: web
platforms: ${{ steps.options.outputs.platforms }}
push: true
build-args: VERSION=${{ steps.options.outputs.version }}
tags: ${{ steps.options.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
25 changes: 25 additions & 0 deletions .github/workflows/deploiy_aws.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ env:
IMAGE: reearth/reearth:nightly
IMAGE_AWS: reearth-test-server:latest

# web
IMAGE_CLASSIC_WEB: reearth/reearth-classic-web:nightly
IMAGE_CLASSIC_WEB_AWS: reearth-classic-web-test-server:latest

jobs:
deploy_server:
name: Deploy server to AWS
Expand All @@ -36,3 +40,24 @@ jobs:
docker pull $IMAGE
docker tag $IMAGE ${{ steps.login-ecr.outputs.registry }}/$IMAGE_AWS
docker push ${{ steps.login-ecr.outputs.registry }}/$IMAGE_AWS

deploy_web:
name: Deploy web to AWS
runs-on: ubuntu-latest
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID || github.events.inputs.keyId }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY || github.events.inputs.secretAccessKey }}
aws-region: us-west-2

- name: Log in to AWS ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1

- name: docker pull, push to ECR
run: |
docker pull $IMAGE_CLASSIC_WEB
docker tag $IMAGE_CLASSIC_WEB ${{ steps.login-ecr.outputs.registry }}/$IMAGE_CLASSIC_WEB_AWS
docker push ${{ steps.login-ecr.outputs.registry }}/$IMAGE_CLASSIC_WEB_AWS
34 changes: 33 additions & 1 deletion .github/workflows/deploy_web_nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ name: deploy-web-nightly
on:
workflow_dispatch:
env:
# Remove after migrating to Cloud Run
REEARTH_URL: test.reearth.dev
GCS_DEST: gs://test.reearth.dev/

GCP_REGION: us-central1

IMAGE: reearth/reearth-classic-web:nightly
IMAGE_GCP: us-central1-docker.pkg.dev/reearth-oss/reearth/reearth-classic-web:nightly
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
jobs:
deploy_test:
# Remove after migrating to Cloud Run
deploy_test_old:
name: Deploy test env
runs-on: ubuntu-latest
if: github.event.repository.full_name == 'reearth/reearth-classic'
Expand All @@ -27,3 +34,28 @@ jobs:
- run: tar -xvf reearth-web_nightly.tar.gz
- name: rsync
run: gsutil -m -h "Cache-Control:no-store" rsync -x "^reearth_config\\.json$|^cesium_ion_token\\.txt$" -dr reearth-web/ $GCS_DEST

deploy_test:
name: Deploy test env
runs-on: ubuntu-latest
if: github.event.repository.full_name == 'reearth/reearth-classic'
steps:
- uses: google-github-actions/auth@v0
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v0
- name: Configure docker
run: gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
- name: docker push
run: |
docker pull $IMAGE
docker tag $IMAGE $IMAGE_GCP
docker push $IMAGE_GCP
- name: Deploy to Cloud Run
run: |
gcloud run deploy reearth-classic-web \
--image $IMAGE_GCP \
--region $GCP_REGION \
--platform managed \
--quiet
13 changes: 13 additions & 0 deletions web/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
*

!docker/
!src/

!.yarnrc.yml
!index.html
!i18next-parser.config.js
!tsconfig.json
!package.json
!published.html
!vite.config.ts
!yarn.lock
73 changes: 73 additions & 0 deletions web/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
FROM node:20.18.0-slim AS builder
WORKDIR /app

ARG NODE_OPTIONS="--max-old-space-size=4096"
ARG GITHUB_SHA
ENV NODE_OPTIONS=$NODE_OPTIONS
ENV GITHUB_SHA=$GITHUB_SHA

RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=cache,target=/root/.npm,sharing=locked \
corepack enable

RUN --mount=type=bind,source=.yarnrc.yml,target=.yarnrc.yml \
--mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=yarn.lock,target=yarn.lock \
--mount=type=cache,target=/root/.yarn,sharing=locked \
yarn install --frozen-lockfile

RUN --mount=type=bind,source=.yarnrc.yml,target=.yarnrc.yml \
--mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=yarn.lock,target=yarn.lock \
--mount=type=bind,source=index.html,target=index.html \
--mount=type=bind,source=published.html,target=published.html \
--mount=type=bind,source=tsconfig.json,target=tsconfig.json \
--mount=type=bind,source=vite.config.ts,target=vite.config.ts \
--mount=type=bind,source=src,target=src \
--mount=type=cache,target=/root/.yarn,sharing=locked \
yarn build

FROM nginx:1.27-alpine
WORKDIR /usr/share/nginx/html

# Quite the Nginx startup logs.
ENV NGINX_ENTRYPOINT_QUIET_LOGS=true

# Default to Cloud Run port.
# Ref: https://cloud.google.com/run/docs/reference/container-contract#port
ENV PORT=8080

# Defaults Google Cloud Load Balancer header.
# Ref: https://cloud.google.com/load-balancing/docs/https#target-proxies
ENV REAL_IP_HEADER=X-Forwarded-For

# Default values.
ENV REEARTH_API=null
ENV REEARTH_AUTH0_AUDIENCE=null
ENV REEARTH_AUTH0_CLIENT_ID=null
ENV REEARTH_AUTH0_DOMAIN=null
ENV REEARTH_CESIUM_ION_ACCESS_TOKEN=null
ENV REEARTH_CLOUD_API=null
ENV REEARTH_CURRENT_TOS=null
ENV REEARTH_DEVELOPER_MODE=null
ENV REEARTH_DOCUMENTATION_URL=null
ENV REEARTH_EARLY_ACCESS_ADMINS=[]
ENV REEARTH_EXTENSION_URLS=[]
ENV REEARTH_FAVICON_URL=
ENV REEARTH_IP=null
ENV REEARTH_MARKETPLACE_URL=null
ENV REEARTH_MULTI_TENANT=null
ENV REEARTH_PASSWORD_POLICY=null
ENV REEARTH_PLUGINS=null
ENV REEARTH_POLICY=null
ENV REEARTH_PUBLISHED=null
ENV REEARTH_TITLE=
ENV REEARTH_UNSAFE_PLUGIN_URLS=[]

COPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html
COPY --chown=nginx:nginx docker/nginx.conf.template /etc/nginx/templates/nginx.conf.template
COPY --chown=nginx:nginx docker/40-envsubst-on-reearth-config.sh /docker-entrypoint.d
COPY --chown=nginx:nginx docker/reearth_config.json.template /opt/reearth/reearth_config.json.template

ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
38 changes: 38 additions & 0 deletions web/docker/40-envsubst-on-reearth-config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/sh

set -e

# rewrite index.html and published.html to change title and favicon
_REEARTH_HTML_FILE="/usr/share/nginx/html/index.html"
_REEARTH_PUBLISHED_HTML_FILE="/usr/share/nginx/html/published.html"

# Rewrite title tag in index.html only if REEARTH_TITLE is set
if [ -n "$REEARTH_TITLE" ]; then
sed -i -e "s|<title>.*</title>|<title>${REEARTH_TITLE}</title>|g" "$_REEARTH_HTML_FILE"
sed -i -e "s|<title>.*</title>|<title>${REEARTH_TITLE}</title>|g" "$_REEARTH_PUBLISHED_HTML_FILE"
fi

# Rewrite favicon in index.html and published.html only if REEARTH_FAVICON_URL is set
if [ -n "$REEARTH_FAVICON_URL" ]; then
sed -i -e "s|<link rel=\"icon\" href=\"[^\"]*\" />|<link rel=\"icon\" href=\"${REEARTH_FAVICON_URL}\" />|g" "$_REEARTH_HTML_FILE"
sed -i -e "s|<link rel=\"icon\" href=\"[^\"]*\" />|<link rel=\"icon\" href=\"${REEARTH_FAVICON_URL}\" />|g" "$_REEARTH_PUBLISHED_HTML_FILE"
fi

# generate reearth_config.json
_REEARTH_CONFIG_TEMPLATE_FILE="/opt/reearth/reearth_config.json.template"
_REEARTH_CONFIG_OUTPUT_FILE="/usr/share/nginx/html/reearth_config.json"

# Wrap with "" if the value doesn't start with '{[' and end with ']}' (JSON) or "null".
wrap_reearth_variables() {
for var in $(env | grep '^REEARTH_WEB' | cut -d= -f1); do
value=$(printenv "$var")
if [ -z "$value" ]; then
eval "export $var='\"\"'"
elif [ "$value" != "null" ] && [ "$value" != "true" ] && [ "$value" != "false" ] && ! echo "$value" | grep -qE '^\{.*\}$|^\[.*\]$'; then
eval "export $var='\"${value}\"'"
fi
done
}

wrap_reearth_variables "$@"
envsubst < "$_REEARTH_CONFIG_TEMPLATE_FILE" > "$_REEARTH_CONFIG_OUTPUT_FILE"
Loading
Loading