From 9fe20a0e614c82258ce33e70b64c0c252fda13c9 Mon Sep 17 00:00:00 2001 From: Charles Madjeri Date: Wed, 27 Nov 2024 16:07:25 +0100 Subject: [PATCH] feat(project-environment): add mobile app docker build Add: - docker-compose.yml improvments (passing env vars as build args) - Makefile for docker - separated .env files for docker-compose, web and mobile - apk build - apk serving on web client - devops documentation Signed-off-by: Charles Madjeri --- .env.example | 1 + Makefile | 59 +++++++++++ README.md | 11 ++- client_mobile/.env.mobile.example | 24 +++++ client_mobile/.gitignore | 1 + client_mobile/Dockerfile | 26 +++++ client_mobile/pubspec.yaml | 2 +- client_web/.env.example | 5 - client_web/.env.local.example | 24 +++++ client_web/.gitignore | 4 + client_web/Dockerfile | 58 +++++------ client_web/nginx.conf | 3 + docker-compose.yml | 77 ++++++++++----- .../source/{Project => project}/benchmark.rst | 0 docs/source/project/devops/ci_cd.rst | 99 +++++++++++++++++++ docs/source/project/devops/dependencies.rst | 91 +++++++++++++++++ docs/source/project/devops/docker_setup.rst | 69 +++++++++++++ docs/source/project/devops/index.rst | 12 +++ docs/source/{Project => project}/index.rst | 3 +- 19 files changed, 503 insertions(+), 66 deletions(-) create mode 100644 .env.example create mode 100644 Makefile create mode 100644 client_mobile/.env.mobile.example create mode 100644 client_mobile/Dockerfile delete mode 100644 client_web/.env.example create mode 100644 client_web/.env.local.example rename docs/source/{Project => project}/benchmark.rst (100%) create mode 100644 docs/source/project/devops/ci_cd.rst create mode 100644 docs/source/project/devops/dependencies.rst create mode 100644 docs/source/project/devops/docker_setup.rst create mode 100644 docs/source/project/devops/index.rst rename docs/source/{Project => project}/index.rst (96%) diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b86b39a --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +VITE_PORT=8081 \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..35c5e34 --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +# Colors +GREEN := \033[0;32m +YELLOW := \033[0;33m +WHITE := \033[0;37m +RESET := \033[0m + +# Target help text +TARGET_MAX_CHAR_NUM=20 + +.PHONY: start build stop restart reset logs clean help + +PROJECT_IMAGES = area-client-web area-client-mobile + +## Show help +help: + @printf '\n' + @printf 'Usage:\n' + @printf ' $(YELLOW)make$(RESET) $(GREEN)$(RESET)\n' + @printf '\n' + @printf 'Targets:\n' + @awk '/^[a-zA-Z\-\_0-9]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")-1); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + printf " $(YELLOW)%-$(TARGET_MAX_CHAR_NUM)s$(RESET) $(GREEN)%s$(RESET)\n", helpCommand, helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) + @printf '\n' + +## Start containers in detached mode +start: + docker compose up -d + +## Build and start containers in detached mode +build: + docker compose up --build -d + +## Stop all containers +stop: + docker compose down + +## Restart all containers +restart: stop start + +## Reset containers, remove images and rebuild +reset: + docker compose down + docker rmi $(PROJECT_IMAGES) -f + docker compose up --build -d + +## Show container logs +logs: + docker compose logs -f + +## Clean up containers, images, volumes and orphans +clean: + docker compose down --rmi local -v --remove-orphans \ No newline at end of file diff --git a/README.md b/README.md index dfadc88..fc47963 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,16 @@ With AREA, you can create automated workflows that integrate various services an git clone git@github.com:ASM-Studios/AREA.git ``` -2. Install NPM packages +2. Create .env files +- Run the following command to create private env files +```sh +cp .env.example .env +cp client_web/.env.local.example .env.local +cp client_mobile/.env.mobile.example .env.mobile +``` +- Fill the .env, .env.web and .env.mobile files + +3. Install NPM packages ```sh cd AREA/client-web npm install diff --git a/client_mobile/.env.mobile.example b/client_mobile/.env.mobile.example new file mode 100644 index 0000000..965d1d9 --- /dev/null +++ b/client_mobile/.env.mobile.example @@ -0,0 +1,24 @@ +VITE_PORT=8081 +VITE_ENDPOINT=http://localhost:8080 + +VITE_GOOGLE_CLIENT_ID= +VITE_GOOGLE_CLIENT_SECRET= + +VITE_MICROSOFT_CLIENT_ID= + +VITE_LINKEDIN_CLIENT_ID= +VITE_LINKEDIN_CLIENT_SECRET= + +VITE_SPOTIFY_CLIENT_ID= +VITE_SPOTIFY_CLIENT_SECRET= + +# Server URLs +API_URL=http://localhost:8080 +WEB_CLIENT_URL=http://localhost:8081 +MOBILE_CLIENT_URL=http://localhost:8082 + +# OAuth credentials +GITHUB_CLIENT_ID=your_github_client_id +GITHUB_CLIENT_SECRET=your_github_client_secret + +# Add other environment variables as needed \ No newline at end of file diff --git a/client_mobile/.gitignore b/client_mobile/.gitignore index 29a3a50..5b8e2b0 100644 --- a/client_mobile/.gitignore +++ b/client_mobile/.gitignore @@ -41,3 +41,4 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release +.env.mobile \ No newline at end of file diff --git a/client_mobile/Dockerfile b/client_mobile/Dockerfile new file mode 100644 index 0000000..778bcff --- /dev/null +++ b/client_mobile/Dockerfile @@ -0,0 +1,26 @@ +FROM ghcr.io/cirruslabs/flutter:stable + +WORKDIR /app + +ARG VITE_PORT +ARG VITE_ENDPOINT +ARG VITE_GOOGLE_CLIENT_ID +ARG VITE_GOOGLE_CLIENT_SECRET +ARG VITE_MICROSOFT_CLIENT_ID +ARG VITE_LINKEDIN_CLIENT_ID +ARG VITE_LINKEDIN_CLIENT_SECRET +ARG VITE_SPOTIFY_CLIENT_ID +ARG VITE_SPOTIFY_CLIENT_SECRET +ARG API_URL +ARG WEB_CLIENT_URL +ARG MOBILE_CLIENT_URL +ARG GITHUB_CLIENT_ID +ARG GITHUB_CLIENT_SECRET + +COPY . . + +RUN flutter pub get +RUN flutter build apk --release + +RUN mv build/app/outputs/flutter-apk/app-release.apk build/app/outputs/flutter-apk/client.apk +RUN chmod -R 755 build/app/outputs/flutter-apk/ \ No newline at end of file diff --git a/client_mobile/pubspec.yaml b/client_mobile/pubspec.yaml index 8a71de3..664d0f6 100644 --- a/client_mobile/pubspec.yaml +++ b/client_mobile/pubspec.yaml @@ -68,7 +68,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - - .env + - .env.mobile # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg diff --git a/client_web/.env.example b/client_web/.env.example deleted file mode 100644 index 4d4d03a..0000000 --- a/client_web/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -VITE_PORT= -VITE_ENDPOINT= - -VITE_GOOGLE_CLIENT_ID= -VITE_GOOGLE_CLIENT_SECRET= diff --git a/client_web/.env.local.example b/client_web/.env.local.example new file mode 100644 index 0000000..965d1d9 --- /dev/null +++ b/client_web/.env.local.example @@ -0,0 +1,24 @@ +VITE_PORT=8081 +VITE_ENDPOINT=http://localhost:8080 + +VITE_GOOGLE_CLIENT_ID= +VITE_GOOGLE_CLIENT_SECRET= + +VITE_MICROSOFT_CLIENT_ID= + +VITE_LINKEDIN_CLIENT_ID= +VITE_LINKEDIN_CLIENT_SECRET= + +VITE_SPOTIFY_CLIENT_ID= +VITE_SPOTIFY_CLIENT_SECRET= + +# Server URLs +API_URL=http://localhost:8080 +WEB_CLIENT_URL=http://localhost:8081 +MOBILE_CLIENT_URL=http://localhost:8082 + +# OAuth credentials +GITHUB_CLIENT_ID=your_github_client_id +GITHUB_CLIENT_SECRET=your_github_client_secret + +# Add other environment variables as needed \ No newline at end of file diff --git a/client_web/.gitignore b/client_web/.gitignore index 6f522c2..0bb4cfe 100644 --- a/client_web/.gitignore +++ b/client_web/.gitignore @@ -27,3 +27,7 @@ dist-ssr *.sw? .vite/ + +# Environment files +.env +.env.local \ No newline at end of file diff --git a/client_web/Dockerfile b/client_web/Dockerfile index 9b07e3e..2d06b21 100644 --- a/client_web/Dockerfile +++ b/client_web/Dockerfile @@ -16,51 +16,39 @@ RUN curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" \ ###----------------------- Build stage for Node.js application -----------------------### -FROM node:18-alpine AS app-builder +FROM node:latest AS builder WORKDIR /app -# Copy certificates from cert-builder -COPY --from=cert-builder /localhost* ./ - -# Copy only package files first for better layer caching -COPY package*.json ./ +ARG VITE_PORT +ARG VITE_ENDPOINT +ARG VITE_GOOGLE_CLIENT_ID +ARG VITE_GOOGLE_CLIENT_SECRET +ARG VITE_MICROSOFT_CLIENT_ID +ARG VITE_LINKEDIN_CLIENT_ID +ARG VITE_LINKEDIN_CLIENT_SECRET +ARG VITE_SPOTIFY_CLIENT_ID +ARG VITE_SPOTIFY_CLIENT_SECRET +ARG API_URL +ARG WEB_CLIENT_URL +ARG MOBILE_CLIENT_URL +ARG GITHUB_CLIENT_ID +ARG GITHUB_CLIENT_SECRET + +COPY ./package*.json ./ RUN npm install - -# Copy source files and build COPY . . -RUN npm run build - - -###----------------------- Python tools stage -----------------------### -FROM alpine:3.19 AS tools-builder -# Install Python and tools -RUN apk add --no-cache \ - python3 \ - py3-virtualenv \ - py3-pip - -# Setup Python environment -RUN python3 -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install --no-cache-dir sphinx sphinx_rtd_theme +RUN npm run build ###----------------------- Production stage -----------------------### -FROM nginx:alpine +FROM nginx:alpine AS production -# Create directory for mobile builds +COPY --from=builder /app/dist /usr/share/nginx/html +COPY ./nginx.conf /etc/nginx/conf.d/default.conf RUN mkdir -p /usr/share/nginx/html/mobile_builds -# Copy production assets -COPY --from=app-builder /app/dist /usr/share/nginx/html -COPY --from=cert-builder /localhost* /etc/nginx/certs/ -COPY nginx.conf /etc/nginx/conf.d/default.conf - -# Create volume mount point for shared mobile builds -VOLUME /usr/share/nginx/html/mobile_builds - -EXPOSE 8081 +EXPOSE ${VITE_PORT} -CMD ["nginx", "-g", "daemon off;"] +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/client_web/nginx.conf b/client_web/nginx.conf index 9559b2a..036ee9a 100644 --- a/client_web/nginx.conf +++ b/client_web/nginx.conf @@ -4,11 +4,14 @@ server { location / { root /usr/share/nginx/html; + index index.html index.htm; try_files $uri $uri/ /index.html; } # Serve mobile client binary location /client.apk { alias /usr/share/nginx/html/mobile_builds/client.apk; + add_header Content-Type application/vnd.android.package-archive; + add_header Content-Disposition attachment; } } \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index ba5d500..f8dde58 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,32 +1,63 @@ services: - # server: - # build: ./server - # ports: - # - "8080:8080" - # networks: - # - app_network - - # client_mobile: - # build: ./client_mobile - # volumes: - # - client_build:/app/build - # networks: - # - app_network + area-client-mobile: + build: + context: ./client_mobile + dockerfile: Dockerfile + args: + - VITE_PORT + - VITE_ENDPOINT + - VITE_GOOGLE_CLIENT_ID + - VITE_GOOGLE_CLIENT_SECRET + - VITE_MICROSOFT_CLIENT_ID + - VITE_LINKEDIN_CLIENT_ID + - VITE_LINKEDIN_CLIENT_SECRET + - VITE_SPOTIFY_CLIENT_ID + - VITE_SPOTIFY_CLIENT_SECRET + - API_URL + - WEB_CLIENT_URL + - MOBILE_CLIENT_URL + - GITHUB_CLIENT_ID + - GITHUB_CLIENT_SECRET + volumes: + - area-client-data:/app/build/app/outputs/flutter-apk + networks: + - area-network + env_file: + - ./client_mobile/.env.mobile - client_web: - build: ./client_web + area-client-web: + build: + context: ./client_web + dockerfile: Dockerfile + args: + - VITE_PORT + - VITE_ENDPOINT + - VITE_GOOGLE_CLIENT_ID + - VITE_GOOGLE_CLIENT_SECRET + - VITE_MICROSOFT_CLIENT_ID + - VITE_LINKEDIN_CLIENT_ID + - VITE_LINKEDIN_CLIENT_SECRET + - VITE_SPOTIFY_CLIENT_ID + - VITE_SPOTIFY_CLIENT_SECRET + - API_URL + - WEB_CLIENT_URL + - MOBILE_CLIENT_URL + - GITHUB_CLIENT_ID + - GITHUB_CLIENT_SECRET ports: - - "8081:8081" + - "${VITE_PORT}:${VITE_PORT}" volumes: - - client_build:/usr/share/nginx/html/mobile_builds - # depends_on: - # - client_mobile - # - server + - area-client-data:/usr/share/nginx/html/mobile_builds + depends_on: + - area-client-mobile networks: - - app_network + - area-network + env_file: + - ./client_web/.env.local volumes: - client_build: + area-client-data: + networks: - app_network: + area-network: diff --git a/docs/source/Project/benchmark.rst b/docs/source/project/benchmark.rst similarity index 100% rename from docs/source/Project/benchmark.rst rename to docs/source/project/benchmark.rst diff --git a/docs/source/project/devops/ci_cd.rst b/docs/source/project/devops/ci_cd.rst new file mode 100644 index 0000000..bd2da6a --- /dev/null +++ b/docs/source/project/devops/ci_cd.rst @@ -0,0 +1,99 @@ +CI/CD Pipeline +============= + +This page details our Continuous Integration and Continuous Deployment (CI/CD) pipelines implemented using GitHub Actions. + +Documentation Deployment +---------------------- + +Our documentation is automatically built and deployed using GitHub Actions whenever changes are pushed to the main branch. + +Workflow Configuration +~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: yaml + + name: Deploy Documentation + + on: + push: + branches: + - main + paths: + - 'docs/**' + - '.github/workflows/deploy-documentation.yml' + + jobs: + deploy-documentation: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install sphinx sphinx_rtd_theme + + - name: Build documentation + run: | + cd docs + make html + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/build/html + +Workflow Details +~~~~~~~~~~~~~~ + +Triggers +^^^^^^^^ +The workflow is triggered on: + +- Push events to the ``main`` branch +- Changes to files in the ``docs/`` directory +- Changes to the workflow file itself + +Steps Explanation +^^^^^^^^^^^^^^^ + +1. **Checkout Repository** + + - Uses ``actions/checkout@v4`` to clone the repository + - Ensures all documentation source files are available + +2. **Python Setup** + + - Sets up Python environment using ``actions/setup-python@v4`` + - Uses latest Python version + +3. **Dependencies Installation** + + - Upgrades pip to latest version + - Installs Sphinx and Read the Docs theme + +4. **Documentation Build** + + - Changes to docs directory + - Runs ``make html`` to build documentation + - Generates HTML files in ``docs/build/html`` + +5. **GitHub Pages Deployment** + + - Uses ``peaceiris/actions-gh-pages@v3`` + - Deploys built documentation to GitHub Pages + - Uses ``GITHUB_TOKEN`` for authentication + - Publishes content from ``./docs/build/html`` + +Access Points +----------- + +The deployed documentation can be accessed at:``https://asm-studios.github.io/AREA/`` \ No newline at end of file diff --git a/docs/source/project/devops/dependencies.rst b/docs/source/project/devops/dependencies.rst new file mode 100644 index 0000000..f1840eb --- /dev/null +++ b/docs/source/project/devops/dependencies.rst @@ -0,0 +1,91 @@ +Project Dependencies +================== + +This page details all the technologies, tools, and external projects used in our DevOps setup. + +Container Technologies +------------------- + +Docker +~~~~~~ +- **Version**: Latest +- **Usage**: Container orchestration and deployment +- **Purpose**: Ensures consistent development and production environments +- **Source**: `Official Docker `_ + +Docker Compose +~~~~~~~~~~~~ +- **Version**: 3.x +- **Usage**: Multi-container application definition and running +- **Purpose**: Orchestrates our microservices architecture +- **Source**: `Docker Compose `_ + +Web Technologies +-------------- + +Nginx +~~~~~ +- **Version**: Alpine-based +- **Usage**: Web server and reverse proxy +- **Purpose**: Serves web client and handles APK downloads +- **Image**: nginx:alpine +- **Source**: `Official Nginx `_ + +Development Technologies +--------------------- + +Flutter +~~~~~~ +- **Version**: Stable +- **Usage**: Mobile client development +- **Purpose**: Cross-platform mobile application development +- **Image**: ghcr.io/cirruslabs/flutter:stable +- **Source**: `CirrusLabs Flutter `_ + +Node.js +~~~~~~~ +- **Version**: Latest LTS +- **Usage**: Web client development +- **Purpose**: React application building and serving +- **Image**: node:latest +- **Source**: `Official Node.js `_ + +Development Tools +--------------- + +mkcert +~~~~~~ +- **Purpose**: Local SSL certificate generation +- **Usage**: Development SSL certificates +- **Source**: `FiloSottile/mkcert `_ + +Sphinx +~~~~~~ +- **Purpose**: Documentation generation +- **Version**: Latest +- **Usage**: Project documentation +- **Source**: `Sphinx Documentation `_ + +Package Managers +-------------- + +npm +~~~ +- **Purpose**: Node.js package management +- **Used By**: Web client +- **Source**: `npm `_ + +pub +~~~ +- **Purpose**: Flutter/Dart package management +- **Used By**: Mobile client +- **Source**: `pub.dev `_ + +Version Control +------------- + +Git +~~~ +- **Usage**: Source code management +- **Purpose**: Version control and collaboration +- **Source**: `Git `_ \ No newline at end of file diff --git a/docs/source/project/devops/docker_setup.rst b/docs/source/project/devops/docker_setup.rst new file mode 100644 index 0000000..f8262e4 --- /dev/null +++ b/docs/source/project/devops/docker_setup.rst @@ -0,0 +1,69 @@ +Docker Setup +=========== + +Our project uses Docker and Docker Compose for containerization and orchestration. +The following examples could vary depending on the project's environment variables (ports and endpoints). +Here's an overview of our Docker setup: + +Container Structure +----------------- + +The project consists of several Docker containers: + +- **area-client-web**: React-based web client (Port 8081) +- **area-client-mobile**: Flutter-based mobile client +- **shared volumes**: For APK distribution + +Docker Compose Configuration +-------------------------- + +Our ``docker-compose.yml`` defines the following services: + +Client Web +~~~~~~~~~ +.. code-block:: yaml + + area-client-web: + build: ./client_web + ports: + - "8081:8081" + volumes: + - area-client-data:/usr/share/nginx/html/mobile_builds + +Client Mobile +~~~~~~~~~~~~ +.. code-block:: yaml + + area-client-mobile: + build: ./client_mobile + volumes: + - area-client-data:/app/build/app/outputs/flutter-apk + +Volume Management +--------------- + +We use a shared volume ``area-client-data`` to handle APK distribution between containers: + +.. code-block:: yaml + + volumes: + area-client-data: + +This allows the mobile client's APK to be accessible from the web client for downloads. + +Building and Running +------------------ + +To build and run the project: + +.. code-block:: bash + + make start + +Access Points +----------- + +Locally: + +- Web Client: ``http://localhost:8081`` +- Mobile APK Download: ``http://localhost:8081/client.apk`` \ No newline at end of file diff --git a/docs/source/project/devops/index.rst b/docs/source/project/devops/index.rst new file mode 100644 index 0000000..ffeb93f --- /dev/null +++ b/docs/source/project/devops/index.rst @@ -0,0 +1,12 @@ +DevOps Environment +================ + +This section covers the DevOps setup and infrastructure of the AREA project. + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + docker_setup + dependencies + ci_cd \ No newline at end of file diff --git a/docs/source/Project/index.rst b/docs/source/project/index.rst similarity index 96% rename from docs/source/Project/index.rst rename to docs/source/project/index.rst index 977afd1..d76a820 100644 --- a/docs/source/Project/index.rst +++ b/docs/source/project/index.rst @@ -42,5 +42,6 @@ Contents .. toctree:: :maxdepth: 2 + :caption: Project Overview - benchmark + devops/index