[ENG-811] Fix server Dockerfile + create CI workflow to build and publish docker image (#1012)

* Fix server docker build failing due to apt locking error
 - Replace ffmpeg dep with only the libav* and related required lib (reduce size)
 - Add warning to tauri build command when DMG background is missing
 - Minor rust fmt

* Enable assets feature for server Dockerfile
 - Fix web app not using the correct address in prod
 - Add build step for web assets in server Dockerfile

* Enable repository to be defined in server's Dockerfile
 - Enable server's release workflow to specify which repository to build to allow external PRs to work

* Fix pnpm docker cache not working
This commit is contained in:
Vítor Vasconcellos 2023-06-25 12:16:11 -03:00 committed by GitHub
parent 5a790ac996
commit 417d5d3be3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 126 additions and 73 deletions

View file

@ -1,52 +0,0 @@
name: Publish server image
description: Builds the server and publishes its Docker image
runs:
using: 'composite'
steps:
- name: Build web
shell: bash
run: pnpm web build
- name: Build binary & move into Docker context
shell: bash
run: |
cargo build -p server --release
cp ./target/release/server ./apps/server/server
- name: Determine image name & tag
shell: bash
run: |
if [ "$GITHUB_EVENT_NAME" == "release" ]; then
export IMAGE_TAG=${GITHUB_REF##*/}
else
export IMAGE_TAG=$(git rev-parse --short "$GITHUB_SHA")
fi
export GITHUB_REPOSITORY_LOWER=$(echo $GITHUB_REPOSITORY | awk '{print tolower($0)}')
export IMAGE_NAME="ghcr.io/$GITHUB_REPOSITORY_LOWER/server"
echo "IMAGE_NAME=$IMAGE_NAME" >> $GITHUB_ENV
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
echo "Building $IMAGE_NAME:$IMAGE_TAG"
- name: Build Docker image
shell: bash
run: |
docker build ./apps/server --tag $IMAGE_NAME:$IMAGE_TAG
- name: Push Docker image
shell: bash
run: |
docker push $IMAGE_NAME:$IMAGE_TAG
- name: Tag & push image as latest staging image
if: ${{ github.event_name != 'release' }}
shell: bash
run: |
docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:staging
docker push $IMAGE_NAME:staging
- name: Tag & push image as latest production image
if: ${{ github.event_name == 'release' }}
shell: bash
run: |
docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:production
docker push $IMAGE_NAME:production

62
.github/workflows/server.yml vendored Normal file
View file

@ -0,0 +1,62 @@
name: Server release
on:
workflow_dispatch:
jobs:
build-server:
name: Build a docker image for spacedrive server
runs-on: ubuntu-20.04
defaults:
run:
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
install: true
platforms: linux/amd64
driver-opts: |
image=moby/buildkit:master
network=host
- name: Determine image name & tag
shell: bash
run: |
if [ "$GITHUB_EVENT_NAME" == "release" ]; then
export IMAGE_TAG=${GITHUB_REF##*/}
else
export IMAGE_TAG=$(git rev-parse --short "$GITHUB_SHA")
fi
export GITHUB_REPOSITORY_LOWER=$(echo $GITHUB_REPOSITORY | awk '{print tolower($0)}')
export IMAGE_NAME="ghcr.io/$GITHUB_REPOSITORY_LOWER/server"
echo "IMAGE_NAME=$IMAGE_NAME" >> $GITHUB_ENV
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
echo "Building $IMAGE_NAME:$IMAGE_TAG"
- name: Build Docker image
shell: bash
run: |
docker build ./apps/server/docker --tag $IMAGE_NAME:$IMAGE_TAG --build-arg="REPO=${GITHUB_REPOSITORY}" --build-arg="REPO_REF=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
- name: Push Docker image
shell: bash
run: |
docker push $IMAGE_NAME:$IMAGE_TAG
- name: Tag & push image as latest staging image
if: ${{ github.event_name != 'release' }}
shell: bash
run: |
docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:staging
docker push $IMAGE_NAME:staging
- name: Tag & push image as latest production image
if: ${{ github.event_name == 'release' }}
shell: bash
run: |
docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:production
docker push $IMAGE_NAME:production

View file

@ -111,6 +111,11 @@ switch (args[0]) {
process.env.BACKGROUND_FILE_NAME = path.basename(process.env.BACKGROUND_FILE);
process.env.BACKGROUND_CLAUSE = `set background picture of opts to file ".background:${process.env.BACKGROUND_FILE_NAME}"`;
if (!fs.existsSync(process.env.BACKGROUND_FILE))
console.warn(
`WARNING: DMG background file not found at ${process.env.BACKGROUND_FILE}`
);
break;
}
case 'win32':

View file

@ -9,7 +9,11 @@ edition = { workspace = true }
assets = []
[dependencies]
sd-core = { path = "../../core", features = ["ffmpeg", "location-watcher"] }
sd-core = { path = "../../core", features = [
"ffmpeg",
"location-watcher",
"heif",
] }
rspc = { workspace = true, features = ["axum"] }
httpz = { workspace = true, features = ["axum"] }
axum = "0.6.18"

View file

@ -1,3 +1,4 @@
ARG REPO=spacedriveapp/spacedrive
ARG REPO_REF=main
ARG DEBIAN_FRONTEND=noninteractive
@ -18,7 +19,7 @@ RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/
#--
FROM base as build
FROM base as build-base
ARG DEBIAN_FRONTEND
@ -32,27 +33,44 @@ ENV PNPM_HOME="/usr/share/pnpm" \
RUN pnpm env use --global latest
RUN wget -qO- https://sh.rustup.rs | sh -s -- -yq --profile minimal
ENV PATH="/root/.cargo/bin:$PATH"
WORKDIR /srv
ARG REPO REPO_REF
RUN git init spacedrive
RUN git -C spacedrive remote add origin https://github.com/spacedriveapp/spacedrive.git
RUN git -C spacedrive remote add origin "https://github.com/${REPO}.git"
RUN git -C spacedrive fetch --depth=1 origin "$REPO_REF"
RUN git -C spacedrive config advice.detachedHead false
RUN git -C spacedrive checkout FETCH_HEAD
WORKDIR /srv/spacedrive
#--
FROM build-base as web
# Run pnpm install with docker cache
RUN --mount=type=cache,target=/root/.local/share/pnpm/store --mount=type=cache,target=/root/.cache/pnpm/metadata \
pnpm install --frozen-lockfile
RUN pnpm web build
#--
FROM build-base as server
RUN wget -qO- https://sh.rustup.rs | sh -s -- -yq --profile minimal
ENV PATH="/root/.cargo/bin:$PATH"
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
env CI=true .github/scripts/setup-system.sh
RUN --mount=type=cache,target=/root/.cache/prisma/binaries/cli/ \
pnpm prep
RUN cargo build --release -p server
COPY --from=web /srv/spacedrive/apps/web/dist /srv/spacedrive/apps/web/dist
RUN cargo build --features assets --release -p server
#--
@ -67,11 +85,15 @@ ENV TZ=UTC \
LANGUAGE=en \
DATA_DIR=/data
# Note: This needs to happen before the apt call to avoid locking issues with the previous step
COPY --from=server /srv/spacedrive/target/release/server /usr/bin/
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
apt-get install ffmpeg
apt-get install \
libavdevice59 libpostproc56 libswscale6 libswresample4 libavformat59 libavutil57 libavfilter8 \
libavcodec59 libheif1
COPY --chmod=755 entrypoint.sh /usr/bin/
COPY --from=build /srv/spacedrive/target/release/server /usr/bin/
# Expose webserver
EXPOSE 8080

View file

@ -5,8 +5,6 @@ import { RspcProvider } from '@sd/client';
import { Platform, PlatformProvider, SpacedriveInterface, routes } from '@sd/interface';
import demoData from './demoData.json';
const serverOrigin = import.meta.env.VITE_SDSERVER_ORIGIN || 'localhost:8080';
// TODO: Restore this once TS is back up to functionality in rspc.
// const wsClient = createWSClient({
// url: `ws://${serverOrigin}/rspc/ws`
@ -23,17 +21,23 @@ const serverOrigin = import.meta.env.VITE_SDSERVER_ORIGIN || 'localhost:8080';
// ]
// });
const http = import.meta.env.DEV ? 'http' : 'https';
const spacedriveProtocol = `${http}://${serverOrigin}/spacedrive`;
const spacedriveURL = (() => {
const currentURL = new URL(window.location.href);
if (import.meta.env.VITE_SDSERVER_ORIGIN) {
currentURL.host = import.meta.env.VITE_SDSERVER_ORIGIN;
} else if (import.meta.env.DEV) {
currentURL.host = 'localhost:8080';
}
currentURL.pathname = 'spacedrive';
return currentURL.href;
})();
const platform: Platform = {
platform: 'web',
getThumbnailUrlByThumbKey: (keyParts) =>
`${spacedriveProtocol}/thumbnail/${keyParts
.map((i) => encodeURIComponent(i))
.join('/')}.webp`,
`${spacedriveURL}/thumbnail/${keyParts.map((i) => encodeURIComponent(i)).join('/')}.webp`,
getFileUrl: (libraryId, locationLocalId, filePathId) =>
`${spacedriveProtocol}/file/${encodeURIComponent(libraryId)}/${encodeURIComponent(
`${spacedriveURL}/file/${encodeURIComponent(libraryId)}/${encodeURIComponent(
locationLocalId
)}/${encodeURIComponent(filePathId)}`,
openLink: (url) => window.open(url, '_blank')?.focus(),

View file

@ -1,7 +1,5 @@
import { wsBatchLink } from '@rspc/client/v2';
const serverOrigin = import.meta.env.VITE_SDSERVER_ORIGIN || 'localhost:8080';
globalThis.isDev = import.meta.env.DEV;
globalThis.rspcLinks = [
// TODO
@ -9,6 +7,16 @@ globalThis.rspcLinks = [
// enabled: () => getDebugState().rspcLogger
// }),
wsBatchLink({
url: `ws://${serverOrigin}/rspc/ws`
url: (() => {
const currentURL = new URL(window.location.href);
currentURL.protocol = currentURL.protocol === 'https:' ? 'wss:' : 'ws:';
if (import.meta.env.VITE_SDSERVER_ORIGIN) {
currentURL.host = import.meta.env.VITE_SDSERVER_ORIGIN;
} else if (import.meta.env.DEV) {
currentURL.host = 'localhost:8080';
}
currentURL.pathname = 'rspc/ws';
return currentURL.href;
})()
})
];