diff --git a/.github/workflows/push_image_ecr.yml b/.github/workflows/push_image_ecr.yml new file mode 100644 index 00000000..474cd556 --- /dev/null +++ b/.github/workflows/push_image_ecr.yml @@ -0,0 +1,64 @@ +name: Push Prod Image to Amazon ECR + +# when tagging action success +on: + pull_request: + types: + - closed + branches: + - main + +env: + AWS_REGION: ap-northeast-2 + +jobs: + image-build-and-push: + name: Build and Push + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - 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: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + + - name: Login to AWS ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Build Image and Push to AWS ECR + id: build_image_and_push + uses: docker/build-push-action@v5 + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + ECR_REPOSITORY: biseo-server + with: + file: .docker/api.Dockerfile + push: true + tags: | + "${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest" + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + + - name: Remove old cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.prettierignore b/.prettierignore index ee05fcc5..fdcded4a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,5 @@ pnpm-lock.yaml **/dist +deployment/**/*.yaml +.github/**/*.yml +**/*.md diff --git a/deployment/.gitignore b/deployment/.gitignore new file mode 100644 index 00000000..d37e42ce --- /dev/null +++ b/deployment/.gitignore @@ -0,0 +1 @@ +**/secret.yaml \ No newline at end of file diff --git a/deployment/README.md b/deployment/README.md new file mode 100644 index 00000000..89a0b77a --- /dev/null +++ b/deployment/README.md @@ -0,0 +1,32 @@ +# Deployment Resource Definitions for Taxi Backend Service + +### directories +``` +├── README.md +├── base +│ ├── kustomization.yaml +│ ├── db +│ │ ├── deployment.yaml +│ │ └── service.yaml +│ └── server +│ ├── configmap.yaml +│ ├── deployment.yaml +│ ├── ingress.yaml +│ ├── sealed-secret.yaml +│ ├── secret-template.yaml +│ ├── secret.yaml +│ └── service.yaml +└── overlays + └── dev + └── kustomization.yaml +``` + +*under base folder* +- shared resource definitions for all environments + +*under overlay folder* +- environment specific settings +- you can add more environments + +### Using kubeseal +[Document Notion Link](https://www.notion.so/sparcs/K8S-Sealed-Secret-kubeseal-c3e315e429c442bebf8998b048404e17) [sparcs only] \ No newline at end of file diff --git a/deployment/base/kustomization.yaml b/deployment/base/kustomization.yaml new file mode 100644 index 00000000..7c475acd --- /dev/null +++ b/deployment/base/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- ./server/deployment.yaml +- ./server/configmap.yaml +- ./server/service.yaml +- ./server/ingress.yaml +- ./server/sealed-secret.yaml \ No newline at end of file diff --git a/deployment/base/server/configmap.yaml b/deployment/base/server/configmap.yaml new file mode 100644 index 00000000..0ed64f5d --- /dev/null +++ b/deployment/base/server/configmap.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: biseo-env +data: + NODE_ENV: "production" + SERVER_PORT: "8000" + DB_NAME: biseo + DB_USER: mysql + DB_ROOT_HOST: '%' \ No newline at end of file diff --git a/deployment/base/server/deployment.yaml b/deployment/base/server/deployment.yaml new file mode 100644 index 00000000..52b973f4 --- /dev/null +++ b/deployment/base/server/deployment.yaml @@ -0,0 +1,29 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: biseo-server + labels: + app: biseo-server +spec: + replicas: 2 + selector: + matchLabels: + app: biseo-server + template: + metadata: + labels: + app: biseo-server + spec: + containers: + - name: biseo-server + image: 666583083672.dkr.ecr.ap-northeast-2.amazonaws.com/biseo-server:latest + ports: + - containerPort: 8000 + envFrom: + - secretRef: + name: biseo-secret + env: + - name: NODE_ENV + value: "production" + - name: SERVER_PORT + value: "8000" \ No newline at end of file diff --git a/deployment/base/server/ingress.yaml b/deployment/base/server/ingress.yaml new file mode 100644 index 00000000..39e7f9dc --- /dev/null +++ b/deployment/base/server/ingress.yaml @@ -0,0 +1,34 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + alb.ingress.kubernetes.io/backend-protocol: HTTP + alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]' + alb.ingress.kubernetes.io/ssl-redirect: '443' + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/healthcheck-path: /api + alb.ingress.kubernetes.io/target-type: 'instance' + alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:666583083672:certificate/2f5020e0-01dd-43dd-aa7e-0699015d6b89 + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-2016-08 + name: biseo-ingress + namespace: biseo + finalizers: + - ingress.k8s.aws/resources + labels: + app: biseo-ingress +spec: + ingressClassName: alb + rules: + - host: biseo-staging.sparcs.org + http: + paths: + - path: / + backend: + service: + name: biseo-svc + port: + number: 8000 + pathType: Prefix + tls: + - hosts: + - biseo-staging.sparcs.org diff --git a/deployment/base/server/sealed-secret.yaml b/deployment/base/server/sealed-secret.yaml new file mode 100644 index 00000000..08936725 --- /dev/null +++ b/deployment/base/server/sealed-secret.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + creationTimestamp: null + name: biseo-secret + namespace: biseo +spec: + encryptedData: + DB_PASSWORD: AgDQqGE3NnusAsJkHwP6MC39ZJlmN184ABTCC6CspSVaSZH8xfMFg4QD1G1i82rj1drWjmcL+U++zEtWXQruVocmACbBoE4AtRr9TbDpfRNKXJ4zCR0aU56t6NP07JUma6ON0HO7RKqv5Dx7+BE8eriKq+Ye8AEm9YbDHQgZ/vsRcBQpwY/qoIPZiFyc7yb/sIGEUmBDDURT6EAgHAhF6Ys+BB6K0Zt1diqKsyEuGj5G0UEVADiuv8Ijhog33Ni7VvCkAmVK6dVis05JE08HEAUuBplqu/WN1lrsP4UXcid0Rtn03my32B/e+mvljXlQiKcBFGeGhD+cKrd3XgSn/QpxpggIZ3+TzxdhWIfg5L6HGdlG6jU205S4Gc2UAyVIsxzUv+mKUg1/XWSKa2I0vQ4nk8nvan8MOtduu0v8pOQc8Zr/1qaHI3fMuXlUSki6++h3j84aiBmnBBpQwZg0npqNnb/S/4s0Lya5m8TA5xITLD3BovUZ+vzKqvbwTPt1vjBb4GTVg7UDnz7PoSFHLW5A+A/B+UoBpW4qJK7UhNnagBWe/djCsRxexApkC/x5Z7Xjroxr6/8Xw3ncAIbn7jKur3HgCjQLVsz8SoD+zuFiaOm939FonlQ5T5EQZJqC1oxJaPUPkKedxW73x39CD4HMbHJrchqEbkQJ/kpOUFeAnu4cMZiYBPWjg6FHNeI2ictExiiN + DB_URL: AgAhPXnLilS6ibEvkHK4Y5wa2HXoIPbWm3thLaSxi2x+1gwJmBqUd6tf6zzyweQtdSrlDX7Q8KGJ+fT1IUNDnG0rDAUceeObatX44l5q18YxG23EoB+jAm9su4DFmArZOXLd4W9eY1vm0cEGYJklpMYM5hztVc/MvlB9lqh0kGmyfPSFU4QL5zXg562Iu8kyrvbOM8BnqmEj5epfikusSIxO4UBC8UjC+B2Uh0FfOJvqTzZzPUjcaqWIrajE20lSZyCP+oKWbFGP8OWT47zaBPYuTgAGYrPEOAcXiP6EUJJhg29DbK/n/YPx31BcWIH7FJG+406NpL2uzk8qjmPO2wee9Q0VBn2kdluAxP28J9TcsNxpKFgYfTiMB8lPR/jxwYTd3uH81LMh8FObRR8IB3zuleeRPsHRFNr0i5ZNgjgf7JvIKhtEZNpazeBK+EiIOuMsM1Dy8u3U6HcSHjP/fdV19JGWUC5VwqlwsPyfFGl5LaGMh+lYHl0J5tjRzdKltZJqcjNhNLIa1LwG/bsLlQQPzK2Z8MxU24pX73/UGqgr9L9bnai5eiP84PU2g6K2rmgLo7OfbgrtKQZn/9TCA3JZBeL1VtFtAx1LG89K5a7NFfmUB5CT2VaKO+hqKzwEjmf0GjAnrKDxGUeQtGTYiW+kN3ngjBFz4WlyQaRceRv3xhLT8usJ6556CoKoBMwx0+5bfC6UOhS8FAbgT9EUU9CXneWQJ+SYamYRTO4APzWmY95IHHqf + SECRET_KEY: AgA1OaVQrQh7xJ53dRc4yb3cgqIBKf9bifM/g2bor6FTjO0/0mYIiEOhly+WRfGmJD2BUcM6Zi3bNULl0cCZTImNfGkTCAr4zF/CCpIsZ2dR2nthwaMjBVGGghTcuAgYE1bo8AtawSm+/RrJWNgPhjcg+mfuFM8d4SS+CsO4PH9yKHIZrb/Be1LJ2zdrXc/1S6rrsbjwC2dDCaFcXiCcdkCoIQzBMVC2xfQ0QXOnSMnZtF7UOu8M3iYGFdHdMrWLYgW94AjtpSEr+19glZo4ZkMSswcPAw2TZWT8pd9Dn4TfOctS/eUGGmCVKsFdre5q937/oL14PN+RREOwEaMdK7qPnJ5XZAY5RpFmw4WUWMBMz5plqliIbLNkPlV/3WoTDvsyDJ5Z6LrVf62/VGAlasChaQ8b8Nn2LuEprSZoHlmOFabraUE+UOF5BupW3up/MEBT9tCekSZSH96KpE8/QB3qyr4yHEhbN9mJUYJd4pwHf/b8K26c5a0dnLBIo73fKof+wm/7E8734v1Zb0tae/ZKcpHYa4+7UIS6beGPksV5zfM6eW82oSCG74uhoMKNLreaAVZUeO9UAJRg5fW1CxymeaTZEUVOZNqPjQclDnUPrfbuovfO9dcjoqKhTDOa12X3t/s3Cn+HA+GqObWpWPGMclVtQ2y+mK9RZI0BTCOGHaBPAzPa73szboBGwE26OgovgOGwMw== + rootHost: AgAlhEkc4mCV1BbzDpFnP+aLW/Gmfo2Oq9sPj++E09nJg1mEEfzbWxjosZECOPFPJQKZCJT7z8KUxVRSa0UZ2kmvFwPeDnQDKSJmXcIl1iwn6PU1XgE6n0L/f+gRNkNmJ3+OYCKnUlGvisIFd913IDjL3/sQ7IEYXRt1UoRChF53k/Z7G7ub7CkBG2Vv4Ghmid2nzYJwitDrPVb/CGdoLAxvU1CEeJcifbZIR6ZZJQ+4D94m1WzVIGAXRU9uggQZGQpsj8Xk+USGbzAa+oKh2o+Oa2iDaGFLCq0Ue6k/2A/AtEbBzqBfCFTfMzPiP+mIRQwCmKfeGfy7YLwzdLiZl101VJWCW5S3iHg5JAivpuMBcwvUQFf/9nzPvoKygXBh5nQAonP7ddhCDtI+PEE8R09jJiKYaLjWn1lsg+HcW2IwLmUFOh1OF2PxmKJhiN8V517yzfXB9i2pZ6T0rcD0qpEzlRrJZ9DhFOdVcIRtCGAsDQXkJ1MBa61+gN/7la9Rry+iCxYJ7/L1DBzalZygSlnqoVTaGbFVmf+G0N2pUXRATnvH6X/px0zF3ffwq40fIkpj5a/0zazqmkUvpRbeCs5rDNRQNmuVMo3j+elRbqvXRYXcWTf/LT9zyVZIHahzDVnGdQ6Djh1udpliBU8pzQJsvrFcAZEkQ/xq3b1pwRb9Lkzf9gM3qtdibRIZr2VNLMWP + rootPassword: AgCPAEcagvd9tBjNdb/xPMsDLrgVooYEZXU3stUf5d6ozJdEpj8v+m1/98ktVSOAmofu2CtDqjWJyPhB00238aLaOzcQNvfDrt25GOsWW+mxuQVhgSsxuBDO8zVuR1dme3z+sy5xyy7Nh4FGmeiEH38Tyep827TTqCGRWwv0QLcesoakgt3qvW5NJ4TXR4dVGz4ybTIQ9g+cTuzQD80i0l00eXnzic3OXkTQFdcLgHBkK4agYGQ02dSfxtrkYrQqk9mVoxQAmaXZa5jcSbmzWt3l5FL6JWrT8OLb1Qcucm2a8IaNJhzpY6o53Yackfk2HotbRk3D87srpa454FLbsH/laeAPrIFMwU64jFU12YHwRThMTto1tdBVczBiNXd/2cDVYZ4fhd+vNigJh8LgugsNY7uBNfqGlC4gPcLvrFyH/Ax3nPOkrHLUWT+2YX5htwSYQjedMsak6htw1Z3j6qbnTGgfhlRXnvWAtapJIsT/X5LL5GFtOWREioKhehQ4Nh53dbld897r6TOYbC8rMfW/G33IBj9HfSHvAC3H4DccRP1nEzJ06h7Z7s8IaC7kyI069ert5+QSLhAr+ZZz4ScqAzwoakvN6jHoXpimQPc2typFb7yKraC7Wb8maQ17SopNlLm/S2I7N5xYfyq5oDDimm0+ZkeYKKLAxen3lXg+LUSXFvN4Z1QziiTvsVq/TJfCnSqS + rootUser: AgAMk97SMwm5SBY/OE+1RepQ0w6s7yTYaRAA8nvfP7dHagFqJ23w5EwA8l6KE2JG12YCVpwvrjCd7Y+Z/x0Y4VTjIodyhNK6zQGu+C74s9/4u+ZrKJA9nOyc0cUA1HLGOea567eVfbHooTSSGseF6fts2sbg2NllbRUU3nvflyhIz+CH3quQilDyiSgcYpEefbu1BvDOGeQFSJOz6mh1U+iZyKFprlkPIents6UKRnvdVoJu4sXHzHMyvr8b9EcORaIR8gLemf0QWxpcNEvpjjHBmnJUTaWoNuzh64WAisqNspSEu7Hd3jsXawkJUDkM1IJDS0WUHY99BipmAgr8gFPzZYtJYabQv2P+tBeaKwozYLGWMHV4ZiKdF/Tlbrkoz3LoLdJF0BbO32io+5nyodokYXdc57DwTBTeliI6pRj1tvav8r2ili4X9+Mm7eryg2Bi1TwOtj9KKjs7NcwkWpShUajal4AxT/FsCze6GSZX4cPsFsydHPH5h1kcykfukbeaorvkEYlbe5iXWRTMkYLEhR6rmLxeYZiqbpQ1S/EyMHGUK6lugBNgo/FMV7PztCsNpKdLUjCmrMvXDsKu3sMxSrBl33FKJeSPIoYQHm/PDCzrGk8osO0FmlbinJwnWmipdaEe4M0fz7ldXIDk8F/0j2quQ21qI/d+rsGI1mQb9svPakuDGcxW1M7ZkCda8ixjXZPD + template: + metadata: + creationTimestamp: null + name: biseo-secret + namespace: biseo + type: Opaque diff --git a/deployment/base/server/secret-template.yaml b/deployment/base/server/secret-template.yaml new file mode 100644 index 00000000..5b9e9b7b --- /dev/null +++ b/deployment/base/server/secret-template.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: biseo-secret + namespace: biseo +type: Opaque +data: + DATABASE_URL: base64encodedvalue + DB_PASSWORD: base64encodedvalue + SECRET_KEY: base64encodedvalue \ No newline at end of file diff --git a/deployment/base/server/service.yaml b/deployment/base/server/service.yaml new file mode 100644 index 00000000..aa631c9f --- /dev/null +++ b/deployment/base/server/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: biseo-svc +spec: + type: NodePort + selector: + app: biseo-server + ports: + - protocol: TCP + port: 8000 + targetPort: 8000 \ No newline at end of file diff --git a/deployment/overlays/dev/kustomization.yaml b/deployment/overlays/dev/kustomization.yaml new file mode 100644 index 00000000..3f65ed37 --- /dev/null +++ b/deployment/overlays/dev/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: ghcr.io/sparcs-kaist/biseo-server + newTag: latest +resources: +- ../../base \ No newline at end of file diff --git a/packages/api/prisma/schema.prisma b/packages/api/prisma/schema.prisma index df9cec09..d48e49df 100644 --- a/packages/api/prisma/schema.prisma +++ b/packages/api/prisma/schema.prisma @@ -5,7 +5,7 @@ generator client { datasource db { provider = "mysql" - url = env("DATABASE_URL") + url = env("DB_URL") } model Agenda { diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 8770f561..733a3d8b 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -17,16 +17,19 @@ import { agendaRouter } from "@biseo/api/listener/agenda"; import { agendaTemplateRouter } from "@biseo/api/listener/agenda.template"; import { userTagRouter } from "@biseo/api/listener/user.tag"; +const corsOrigin = + env.NODE_ENV === "development" ? "*" : [/sparcs\.org$/, /kaist\.ac\.kr$/]; + const app = express(); const httpServer = createServer(app); const io: BiseoServer = new Server(httpServer, { path: "/api/socket", - cors: { origin: "*" }, + cors: { origin: corsOrigin }, }); const port = env.SERVER_PORT ?? 8000; app.use(express.json()); -app.use(cors()); +app.use(cors({ origin: corsOrigin })); app.get("/api", (req, res) => { res.send("Hello World!");