Deployment dengan Docker dan GitHub Actions
Membagikan pengalaman saya mendeploy suatu project dengan Docker dan GitHub Actions.
Bicara mengenai deployment, saya sudah cukup banyak mencoba cukup banyak cara. Mulai dari drag & drop ke cPanel, deploy langsung ke VPS dengan process manager (pm2), hingga yang paling mudah dengan sekali klik seperti Vercel atau Netlify.
Pada tulisan ini, saya ingin berbagi pengalaman saat mencoba deployment ke VPS menggunakan Docker.
Kenapa Docker?
Docker adalah tool yang powerful untuk meng-containerize aplikasi kita. Dengan Docker, kita bisa menyiapkan environment aplikasi dalam satu container tanpa perlu mengubah konfigurasi di VPS secara langsung.
Saya sudah merasakan bagaimana rumitnya ketika harus setup di VPS secara langsung ketika mendeploy bot whatsapp (GilBot). Yang membuat rumit adalah karena saya melakukan development di OS Windows yang mana dependensi yang dibutuhkan sudah pre-installed, sehingga bisa run & go. Berbeda ketika saya deploy ke VPS, ternyata muncul banyak error karena menggunakan OS Ubuntu dan perlu cukup banyak dependensi yang perlu diinstall. Karena waktu itu saya belum berani pakai dan eksplor Docker, maka saya membuat bash script untuk menjalankan perintah instalasi dependensi yang dibutuhkan.
Docker & pnpm
Pada kasus project yang saya deploy ke VPS ini menggunakan package manager pnpm yang ternyata membutuhkan konfigurasi tambahan pada Docker-nya. Untungnya pnpm sudah menyediakan dokumentasinya, jadi bisa langsung dicontek saja.
Jadi, kurang lebih Dockerfile yang saya gunakan seperti berikut:
FROM node:20-slim AS base ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN corepack enable COPY . /app WORKDIR /app FROM base AS prod-deps RUN pnpm install --prod --frozen-lockfile FROM base AS build RUN pnpm install --frozen-lockfile RUN pnpm run build FROM base COPY /app/node_modules /app/node_modules COPY /app/dist /app/dist EXPOSE 3000 CMD ["pnpm", "start"]
GitHub Actions
Karena saya menyimpan project di repositori GitHub dan sudah cukup familiar, maka saya memilih GitHub Actions untuk menjalankan CI/CD. Workflow ini akan dijalankan setiap ada push commit ke main
branch dan manual trigger pada menu Actions di repositori.
name: Build & Deploy on: workflow_dispatch: # Trigger the workflow manually push: branches: - main # Trigger the workflow on push to the main branch
Proses Deployment
Dalam job ini kita melakukan build Docker image dan push ke Docker Hub. Kita bisa mendapatkan DOCKER_HUB_TOKEN
melalui Settings > Personal Access Token, DOCKER_HUB_USERNAME
adalah username yang kita buat, dan gilbot-telegram
adalah nama repositori pada Docker Hub.
- name: Build the Docker image run: docker build -t gilbot-telegram . - name: Log in to Docker Hub run: echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin - name: Push Docker image run: docker tag gilbot-telegram ${{ secrets.DOCKER_HUB_USERNAME }}/gilbot-telegram:latest - run: docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gilbot-telegram:latest
Setelah itu, kita setup SSH agent dan deploy ke VPS dengan melakukan pull image dan jalankan container dengan image terbaru. Jangan lupa untuk generate private key (VPS_PRIVATE_KEY
) terlebih dahulu jika belum ada. Isi VPS_USER
dengan username yang terdaftar di server dan VPS_HOST
dengan IP address dari server yang digunakan.
- name: Set up SSH agent for deployment uses: webfactory/ssh-agent@v0.9.0 with: ssh-private-key: ${{ secrets.VPS_PRIVATE_KEY }} - name: Deploy to VPS run: | ssh -o StrictHostKeyChecking=no ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} << 'EOF' # Create .env file with secrets echo "BOT_TOKEN=${{ secrets.BOT_TOKEN }}" > .env echo "DEBUG=grammy:*" >> .env # Pull the latest Docker image docker pull ${{ secrets.DOCKER_HUB_USERNAME }}/gilbot-telegram:latest # Stop and remove existing container if it's running docker stop gilbot-telegram-container || true docker rm gilbot-telegram-container || true # Run the new container docker run -d --name gilbot-telegram-container --env-file .env -p 3000:3000 ${{ secrets.DOCKER_HUB_USERNAME }}/gilbot-telegram:latest EOF
Kode Lengkap Workflow
Berikut adalah keseluruhan workflow yang digunakan:
name: Build & Deploy on: workflow_dispatch: push: branches: - main jobs: build_and_deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Build the Docker image run: docker build -t gilbot-telegram . - name: Log in to Docker Hub run: echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin - name: Push Docker image run: docker tag gilbot-telegram ${{ secrets.DOCKER_HUB_USERNAME }}/gilbot-telegram:latest - run: docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gilbot-telegram:latest - name: Set up SSH agent for deployment uses: webfactory/ssh-agent@v0.9.0 with: ssh-private-key: ${{ secrets.VPS_PRIVATE_KEY }} - name: Deploy to VPS run: | ssh -o StrictHostKeyChecking=no ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} << 'EOF' echo "BOT_TOKEN=${{ secrets.BOT_TOKEN }}" > .env echo "DEBUG=grammy:*" >> .env docker pull ${{ secrets.DOCKER_HUB_USERNAME }}/gilbot-telegram:latest docker stop gilbot-telegram-container || true docker rm gilbot-telegram-container || true docker run -d --name gilbot-telegram-container --env-file .env -p 3000:3000 ${{ secrets.DOCKER_HUB_USERNAME }}/gilbot-telegram:latest EOF
Masalah yang ditemukan
Pada kasus saya di project ini sebenarnya hanya untuk mendeploy sebuah bot telegram. Namun, saya juga coba untuk menambahkan HTTP server untuk bisa menyediakan JSON response. Itulah kenapa saya menambahkan port pada konfigurasi di atas.
Untuk HTTP server-nya sendiri saya menggunakan Fastify dan ketika deploy pertama kali, server mengembalikan empty response saat saya mengakses IP server, yang seharusnya mengembalikan sebuah JSON. Setelah saya telusuri, ternyata kita perlu bind aplikasi ke host 0.0.0.0
ketika menggunakan Docker.
fastify.listen({ host: '0.0.0.0' })
Dan masalah selesai, server bisa diakses melalui IP: 178.62.234.72:3000.
Penutup
Itulah sedikit pengalaman saya ketika melakukan deployment dengan Docker dan GitHub Actions. Bagi saya yang belum terlalu tertarik untuk mendalami masalah deployment dan server ini ternyata cukup rumit, walau pada akhirnya tinggal push dan auto deploy seperti menggunakan Vercel 😋
Docker juga menyediakan cheatsheet untuk mempermudah pengguna baru menjelajahi dan memahami perintah-perintah yang tersedia. Jika kalian ingin mencoba bot telegram yang sedang dalam development ini, bisa mengunjungi: https://t.me/gilchatbot 🤘
Sekian tulisan kali ini, jika ada yang salah mohon diluruskan. Terima kasih 🙏