From 6144c66c8eaa6348febd7c8e0cab41304b85cbc9 Mon Sep 17 00:00:00 2001 From: Varkoff Date: Sat, 21 Sep 2024 21:24:01 +0200 Subject: [PATCH] move to vps --- .dockerignore | 7 ++ .github/workflows/build.yml | 68 ++++++++++++++++ .github/workflows/ci-deploy.yml | 96 ++++++++++++++++++++++ Dockerfile | 19 +++++ docker-compose.dev.yml | 17 ++++ docker-compose.prod.yml | 70 ++++++++++++++++ package-lock.json | 138 ++++++++++++++++++++++++++++++++ package.json | 2 + 8 files changed, 417 insertions(+) create mode 100644 .dockerignore create mode 100755 .github/workflows/build.yml create mode 100755 .github/workflows/ci-deploy.yml create mode 100644 Dockerfile create mode 100644 docker-compose.dev.yml create mode 100644 docker-compose.prod.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..709870d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +/node_modules +*.log +.DS_Store +.env +/.cache +/public/build +/build \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100755 index 0000000..5122498 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,68 @@ +name: 🐳 Build And Push Docker Image +on: + workflow_call: + inputs: + tag: + type: string + description: The tag to push to the Docker registry. + # required: true + # default: latest + +jobs: + build: + name: 🐳 Build + # only build/deploy main branch on pushes + # if: ${{ (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && github.event_name == 'push' }} + if: ${{ (github.ref == 'refs/heads/strapi') && github.event_name == 'push' }} + runs-on: ubuntu-latest + steps: + - name: 🛑 Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.11.0 + + - name: ⬇️ Checkout repo + uses: actions/checkout@v3 + + - name: 🧑‍💻 Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + logout: true + + - name: 🐳 Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + # Setup cache + - name: ⚡️ Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: 🐳 Build Production Image + if: ${{ github.ref == 'refs/heads/main' }} + uses: docker/build-push-action@v3 + with: + context: . + push: true + tags: algomax/ecommerce-frontend:production + build-args: | + COMMIT_SHA=${{ github.sha }} \ + + JWT_SECRET=${{ secrets.JWT_SECRET }} \ + STRAPI_TOKEN=${{ secrets.STRAPI_TOKEN }} \ + STRAPI_URL=${{ secrets.STRAPI_URL }} \ + + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,mode=max,dest=/tmp/.buildx-cache-new + + # This ugly bit is necessary if you don't want your cache to grow forever + # till it hits GitHub's limit of 5GB. + # Temp fix + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: 🚚 Move cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.github/workflows/ci-deploy.yml b/.github/workflows/ci-deploy.yml new file mode 100755 index 0000000..9d0ac46 --- /dev/null +++ b/.github/workflows/ci-deploy.yml @@ -0,0 +1,96 @@ +name: 🚀 Deploy +on: + push: + branches: + - main + - dev + pull_request: {} + +permissions: + actions: write + contents: read + +jobs: + # lint: + # name: ⬣ ESLint + # runs-on: ubuntu-latest + # steps: + # - name: 🛑 Cancel Previous Runs + # uses: styfle/cancel-workflow-action@0.11.0 + + # - name: ⬇️ Checkout repo + # uses: actions/checkout@v3 + # # - name: Setup Bun + # # uses: oven-sh/setup-bun@v1 + # # - name: Install dependencies + # # run: npm install + + # - name: ⎔ Setup node + # uses: actions/setup-node@v3 + # with: + # node-version: 20 + + # - name: 📥 Download deps + # uses: bahmutov/npm-install@v1 + # - name: Install dependencies + # run: npm install + + # - name: 🔬 Lint + # run: npm run lint + + # build: + # name: 🐳 build + # uses: ./.github/workflows/build.yml + # secrets: inherit + + deploy: + name: 🚀 Deploy + runs-on: [self-hosted] + # needs: [build] + # only build/deploy main branch on pushes + if: ${{ (github.ref == 'refs/heads/main') && github.event_name == 'push' }} + env: + JWT_SECRET: ${{ secrets.JWT_SECRET }} + STRAPI_TOKEN: ${{ secrets.STRAPI_TOKEN }} + STRAPI_URL: ${{ secrets.STRAPI_URL }} + + steps: + - name: 🛑 Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.11.0 + + - name: ⬇️ Checkout repo + uses: actions/checkout@v3 + + # - name: Login to Docker Hub + # uses: docker/login-action@v2 + # with: + # username: ${{ secrets.DOCKERHUB_USERNAME }} + # password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: 🚀 Run Docker Compose on Production + if: ${{ github.ref == 'refs/heads/main' }} + run: | + touch .env + echo "STRAPI_URL=${{ secrets.STRAPI_URL}}" >> .env + echo "DATABASE_CLIENT=${{ secrets.DATABASE_CLIENT}} >> .env + echo "DATABASE_HOST=strapiDB + echo "DATABASE_PORT=${{ secrets.DATABASE_PORT}} >> .env + echo "DATABASE_NAME=${{ secrets.DATABASE_NAME}} >> .env + echo "DATABASE_USERNAME=${{ secrets.DATABASE_USERNAME}} >> .env + echo "DATABASE_PASSWORD=${{ secrets.DATABASE_PASSWORD}} >> .env + echo "JWT_SECRET=${{ secrets.JWT_SECRET}} >> .env + echo "ADMIN_JWT_SECRET=${{ secrets.ADMIN_JWT_SECRET}} >> .env + echo "APP_KEYS=${{ secrets.APP_KEYS}} >> .env + echo "NODE_ENV=${{ secrets.NODE_ENV}} >> .env + echo "STRAPI_TOKEN=${{ secrets.STRAPI_TOKEN}} >> .env + echo "MAILGUN_API_KEY=${{ secrets.MAILGUN_API_KEY}} >> .env + echo "MAILGUN_DOMAIN=${{ secrets.MAILGUN_DOMAIN}} >> .env + echo "MAILGUN_URL=${{ secrets.MAILGUN_URL}} >> .env + echo "STRIPE_SECRET_KEY=${{ secrets.STRIPE_SECRET_KEY}} >> .env + echo "STRIPE_PUBLISHABLE_KEY=${{ secrets.STRIPE_PUBLISHABLE_KEY}} >> .env + echo "STRAPI_URL=${{ secrets.STRAPI_URL}} >> .env + echo "FRONTEND_URL=${{ secrets.FRONTEND_URL}} >> .env + echo "STRIPE_WEBHOOK_SECRET_KEY=${{ secrets.STRIPE_WEBHOOK_SECRET_KEY}} >> .env + + docker compose -f docker-compose.prod.yml up --build -d + docker system prune --all --volumes --force diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..abfc1d1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM node:18-alpine3.18 +# Installing libvips-dev for sharp Compatibility +RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev git +ARG NODE_ENV=development +ENV NODE_ENV=${NODE_ENV} + +WORKDIR /opt/ +COPY package.json package-lock.json ./ +RUN npm install -g node-gyp +RUN npm config set fetch-retry-maxtimeout 600000 -g && npm install +ENV PATH /opt/node_modules/.bin:$PATH + +WORKDIR /opt/app +COPY . . +RUN chown -R node:node /opt/app +USER node +RUN ["npm", "run", "build"] +EXPOSE 1337 +CMD ["npm", "run", "develop"] diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..ef76816 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,17 @@ +services: + ecommerce_development: + environment: + - JWT_SECRET + - STRAPI_TOKEN + - STRAPI_URL + + container_name: ecommerce_website_development + # image: algomax/ecommerce-frontend:development + build: + context: . + dockerfile: Dockerfile + restart: always + ports: + - '3000:3000' + volumes: + - ./image-cache:/app/image-cache diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..cc16af4 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,70 @@ +version: "3" +services: + strapi: + container_name: strapi + build: . + image: strapi:latest + restart: unless-stopped + env_file: .env + environment: + - DATABASE_CLIENT + - DATABASE_HOST=strapiDB + - DATABASE_PORT + - DATABASE_NAME + - DATABASE_USERNAME + - DATABASE_PASSWORD + - JWT_SECRET + - ADMIN_JWT_SECRET + - APP_KEYS + - NODE_ENV + + - STRAPI_TOKEN + - MAILGUN_API_KEY + - MAILGUN_DOMAIN + - MAILGUN_URL + - STRIPE_SECRET_KEY + - STRIPE_PUBLISHABLE_KEY + - STRAPI_URL + - FRONTEND_URL + - STRIPE_WEBHOOK_SECRET_KEY + + volumes: + - ./config:/opt/app/config + - ./src:/opt/app/src + - ./package.json:/opt/package.json + - ./package-lock.json:/opt/package-lock.json + - ./.env:/opt/app/.env + - ./public/uploads:/opt/app/public/uploads + ports: + - "1337:1337" + networks: + - strapi + depends_on: + - strapiDB + + strapiDB: + container_name: strapiDB + platform: linux/amd64 #for platform error on Apple M1 chips + restart: unless-stopped + env_file: .env + image: postgres:12.0-alpine + environment: + POSTGRES_USER: ${DATABASE_USERNAME} + POSTGRES_PASSWORD: ${DATABASE_PASSWORD} + POSTGRES_DB: ${DATABASE_NAME} + volumes: + - strapi-data:/var/lib/postgresql/data/ #using a volume + #- ./data:/var/lib/postgresql/data/ # if you want to use a bind folder + + ports: + - "5432:5432" + networks: + - strapi + +volumes: + strapi-data: + +networks: + strapi: + name: Strapi + driver: bridge diff --git a/package-lock.json b/package-lock.json index 5d6c1a0..d8219db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@strapi/provider-email-mailgun": "5.0.0", "@strapi/strapi": "5.0.0", "better-sqlite3": "9.4.3", + "pg": "^8.13.0", "react": "^18.0.0", "react-dom": "^18.0.0", "react-router-dom": "^6.0.0", @@ -14869,12 +14870,101 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "node_modules/pg": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.0.tgz", + "integrity": "sha512-34wkUTh3SxTClfoHB3pQ7bIMvw9dpFU1audQQeZG837fmHfHpr14n/AELVDoOYVDW2h5RDWU78tFjkD+erSBsw==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.7.0", + "pg-pool": "^3.7.0", + "pg-protocol": "^1.7.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "license": "MIT", + "optional": true + }, "node_modules/pg-connection-string": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.1.tgz", "integrity": "sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==", "license": "MIT" }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz", + "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", + "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/pg-connection-string": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", + "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", + "license": "MIT" + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", @@ -15472,6 +15562,45 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prebuild-install": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", @@ -17833,6 +17962,15 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", diff --git a/package.json b/package.json index df65eb6..7170bf5 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "description": "A Strapi application", "scripts": { "dev": "strapi develop", + "develop": "strapi develop", "start": "strapi start", "build": "strapi build", "strapi": "strapi", @@ -24,6 +25,7 @@ "@strapi/provider-email-mailgun": "5.0.0", "@strapi/strapi": "5.0.0", "better-sqlite3": "9.4.3", + "pg": "^8.13.0", "react": "^18.0.0", "react-dom": "^18.0.0", "react-router-dom": "^6.0.0",