From 9ce3d1150d7c688d3c08bfadf8e59007fb1538c4 Mon Sep 17 00:00:00 2001
From: Francisco Bischoff <984592+franzbischoff@users.noreply.github.com>
Date: Thu, 7 Mar 2024 00:34:45 +0000
Subject: [PATCH] Update Ubuntu base image and improve Dockerfile (#609)

* Update Ubuntu base image and improve Dockerfile

* Add unzip to Docker image dependencies

Needed for the arm64 build

* reset tabs

* formalized lint rules for hadolint. however the Docker formatting is being handled by MS Docker extension which doesn't indent code as expected. WIP.

* found a workaround to keep formatting

---------

Co-authored-by: timothycarambat <rambat1010@gmail.com>
---
 .hadolint.yaml               |  8 +++++
 .vscode/settings.json        |  5 ++--
 docker/Dockerfile            | 58 +++++++++++++++++++++++++-----------
 docker/docker-entrypoint.sh  | 11 +++----
 docker/docker-healthcheck.sh | 10 +++----
 5 files changed, 62 insertions(+), 30 deletions(-)
 create mode 100644 .hadolint.yaml

diff --git a/.hadolint.yaml b/.hadolint.yaml
new file mode 100644
index 000000000..b76a51072
--- /dev/null
+++ b/.hadolint.yaml
@@ -0,0 +1,8 @@
+failure-threshold: warning
+ignored:
+  - DL3008
+  - DL3013
+format: tty
+trustedRegistries:
+  - docker.io
+  - gcr.io
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 02e25ceed..72b612b86 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -18,5 +18,6 @@
     "Weaviate",
     "Zilliz"
   ],
-  "eslint.experimental.useFlatConfig": true
-}
\ No newline at end of file
+  "eslint.experimental.useFlatConfig": true,
+  "docker.languageserver.formatter.ignoreMultilineInstructions": true
+}
diff --git a/docker/Dockerfile b/docker/Dockerfile
index b1ea62a63..2edbadb2c 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -1,12 +1,17 @@
 # Setup base image
-FROM ubuntu:jammy-20230522 AS base
+FROM ubuntu:jammy-20230916 AS base
 
+# Build arguments
 ARG ARG_UID=1000
 ARG ARG_GID=1000
 
 FROM base AS build-arm64
 RUN echo "Preparing build of AnythingLLM image for arm64 architecture"
 
+SHELL ["/bin/bash", "-o", "pipefail", "-c"]
+
+# Install system dependencies
+# hadolint ignore=DL3008,DL3013
 RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
     DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
         unzip curl gnupg libgfortran5 libgbm1 tzdata netcat \
@@ -25,8 +30,8 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
         && rm yarn_1.22.19_all.deb
 
 # Create a group and user with specific UID and GID
-RUN groupadd -g $ARG_GID anythingllm && \
-    useradd -u $ARG_UID -m -d /app -s /bin/bash -g anythingllm anythingllm && \
+RUN groupadd -g "$ARG_GID" anythingllm && \
+    useradd -l -u "$ARG_UID" -m -d /app -s /bin/bash -g anythingllm anythingllm && \
     mkdir -p /app/frontend/ /app/server/ /app/collector/ && chown -R anythingllm:anythingllm /app
 
 # Copy docker helper scripts
@@ -61,6 +66,10 @@ RUN echo "Done running arm64 specific installtion steps"
 FROM base AS build-amd64
 RUN echo "Preparing build of AnythingLLM image for non-ARM architecture"
 
+SHELL ["/bin/bash", "-o", "pipefail", "-c"]
+
+# Install system dependencies
+# hadolint ignore=DL3008,DL3013
 RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
     DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
         curl gnupg libgfortran5 libgbm1 tzdata netcat \
@@ -79,8 +88,8 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
         && rm yarn_1.22.19_all.deb
 
 # Create a group and user with specific UID and GID
-RUN groupadd -g $ARG_GID anythingllm && \
-    useradd -u $ARG_UID -m -d /app -s /bin/bash -g anythingllm anythingllm && \
+RUN groupadd -g "$ARG_GID" anythingllm && \
+    useradd -l -u "$ARG_UID" -m -d /app -s /bin/bash -g anythingllm anythingllm && \
     mkdir -p /app/frontend/ /app/server/ /app/collector/ && chown -R anythingllm:anythingllm /app
 
 # Copy docker helper scripts
@@ -95,6 +104,8 @@ RUN chmod +x /usr/local/bin/docker-entrypoint.sh && \
 #############################################
 # COMMON BUILD FLOW FOR ALL ARCHS
 #############################################
+
+# hadolint ignore=DL3006
 FROM build-${TARGETARCH} AS build
 RUN echo "Running common build flow of AnythingLLM image for all architectures"
 
@@ -102,43 +113,54 @@ USER anythingllm
 WORKDIR /app
 
 # Install frontend dependencies
-FROM build as frontend-deps
+FROM build AS frontend-deps
 
 COPY ./frontend/package.json ./frontend/yarn.lock ./frontend/
-RUN cd ./frontend/ && yarn install --network-timeout 100000 && yarn cache clean
+WORKDIR /app/frontend
+RUN yarn install --network-timeout 100000 && yarn cache clean
+WORKDIR /app
 
 # Install server dependencies
-FROM build as server-deps
+FROM build AS server-deps
 COPY ./server/package.json ./server/yarn.lock ./server/
-RUN cd ./server/ && yarn install --production --network-timeout 100000 && yarn cache clean
+WORKDIR /app/server
+RUN yarn install --production --network-timeout 100000 && yarn cache clean
+WORKDIR /app
 
 # Compile Llama.cpp bindings for node-llama-cpp for this operating system.
 USER root
-RUN cd ./server && npx --no node-llama-cpp download
+WORKDIR /app/server
+RUN npx --no node-llama-cpp download
+WORKDIR /app
 USER anythingllm
 
 # Build the frontend
-FROM frontend-deps as build-stage
+FROM frontend-deps AS build-stage
 COPY ./frontend/ ./frontend/
-RUN cd ./frontend/ && yarn build && yarn cache clean
+WORKDIR /app/frontend
+RUN yarn build && yarn cache clean
+WORKDIR /app
 
 # Setup the server
-FROM server-deps as production-stage
+FROM server-deps AS production-stage
 COPY --chown=anythingllm:anythingllm ./server/ ./server/
 
 # Copy built static frontend files to the server public directory
-COPY --from=build-stage /app/frontend/dist ./server/public
+COPY --chown=anythingllm:anythingllm --from=build-stage /app/frontend/dist ./server/public
 
 # Copy the collector
 COPY --chown=anythingllm:anythingllm ./collector/ ./collector/
 
 # Install collector dependencies
+WORKDIR /app/collector
 ENV PUPPETEER_DOWNLOAD_BASE_URL=https://storage.googleapis.com/chrome-for-testing-public 
-RUN cd /app/collector && yarn install --production --network-timeout 100000 && yarn cache clean
+RUN yarn install --production --network-timeout 100000 && yarn cache clean
 
 # Migrate and Run Prisma against known schema
-RUN cd ./server && npx prisma generate --schema=./prisma/schema.prisma
-RUN cd ./server && npx prisma migrate deploy --schema=./prisma/schema.prisma
+WORKDIR /app/server
+RUN npx prisma generate --schema=./prisma/schema.prisma && \
+    npx prisma migrate deploy --schema=./prisma/schema.prisma
+WORKDIR /app
 
 # Setup the environment
 ENV NODE_ENV=production
@@ -152,4 +174,4 @@ HEALTHCHECK --interval=1m --timeout=10s --start-period=1m \
   CMD /bin/bash /usr/local/bin/docker-healthcheck.sh || exit 1
 
 # Run the server
-ENTRYPOINT ["/bin/bash", "/usr/local/bin/docker-entrypoint.sh"]
\ No newline at end of file
+ENTRYPOINT ["/bin/bash", "/usr/local/bin/docker-entrypoint.sh"]
diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh
index 3d890db1d..1ac69e5ba 100755
--- a/docker/docker-entrypoint.sh
+++ b/docker/docker-entrypoint.sh
@@ -1,9 +1,10 @@
 #!/bin/bash
-{ cd /app/server/ &&\
-  npx prisma generate --schema=./prisma/schema.prisma &&\
-  npx prisma migrate deploy --schema=./prisma/schema.prisma &&\
-  node /app/server/index.js
+{
+  cd /app/server/ &&
+    npx prisma generate --schema=./prisma/schema.prisma &&
+    npx prisma migrate deploy --schema=./prisma/schema.prisma &&
+    node /app/server/index.js
 } &
 { node /app/collector/index.js; } &
 wait -n
-exit $?
\ No newline at end of file
+exit $?
diff --git a/docker/docker-healthcheck.sh b/docker/docker-healthcheck.sh
index 45a88477d..49bee3e1b 100644
--- a/docker/docker-healthcheck.sh
+++ b/docker/docker-healthcheck.sh
@@ -4,10 +4,10 @@
 response=$(curl --write-out '%{http_code}' --silent --output /dev/null http://localhost:3001/api/ping)
 
 # If the HTTP response code is 200 (OK), the server is up
-if [ $response -eq 200 ]; then
-    echo "Server is up"
-    exit 0
+if [ "$response" -eq 200 ]; then
+  echo "Server is up"
+  exit 0
 else
-    echo "Server is down"
-    exit 1
+  echo "Server is down"
+  exit 1
 fi
-- 
GitLab