Try   HackMD

Docker Material

Introduction

Application Architecture

Arsitektur Aplikasi Modern

Di era digital yang terus berkembang pesat ini, arsitektur aplikasi telah mengalami banyak evolusi. Gone are the days di mana kita mengembangkan aplikasi sebagai satu blok monolitik besar, yang mana segala fitur dan fungsionalitasnya dikemas dalam satu paket raksasa. Sekarang, kita beralih ke pendekatan yang lebih modular dan fleksibel, yaitu arsitektur berbasis microservices.

Microservices adalah sebuah pendekatan dalam pengembangan software di mana aplikasi dibangun sebagai kumpulan layanan yang lebih kecil, mandiri, dan bisa di-deploy secara independen. Setiap layanan ini memiliki fungsionalitas spesifik, berkomunikasi dengan layanan lainnya melalui API yang terdefinisi dengan baik, biasanya melalui HTTP/REST atau messaging queues.

Keuntungan Arsitektur Microservices

  • Fleksibilitas dalam Pengembangan: Dengan memecah aplikasi menjadi layanan-layanan yang lebih kecil, tim pengembangan bisa bekerja secara independen dan paralel, meningkatkan kecepatan dan efisiensi pengembangan.
  • Skalabilitas: Microservices memudahkan skalabilitas aplikasi karena setiap layanan bisa diskalakan secara independen, tergantung kebutuhan.
  • Kemudahan dalam Pemeliharaan: Memperbarui atau memperbaiki bug pada sistem berbasis microservices lebih mudah dan cepat karena hanya perlu fokus pada layanan tertentu, tanpa harus mengutak-atik keseluruhan aplikasi.
  • Resiliensi: Jika satu layanan mengalami masalah, tidak akan langsung mengganggu layanan lain atau aplikasi secara keseluruhan, membuat sistem lebih tahan terhadap error.

Deployment Patterns

Era Deployment Tradisional

Zaman dulu, ngirim atau deploy aplikasi ke lingkungan produksi itu sering kali dilakukan secara manual. Prosesnya bisa panjang dan penuh dengan risiko. Mulai dari transfer file secara manual, konfigurasi server, sampai melakukan restart layanan secara langsung di server produksi. Proses ini tidak hanya memakan waktu, tapi juga rentan terhadap human error yang bisa menyebabkan downtime atau masalah serius lainnya.

Docker muncul sebagai alat yang mempermudah proses deployment aplikasi. Dengan menggunakan kontainer, Docker memastikan bahwa aplikasi akan berjalan dengan konsisten di berbagai lingkungan, dari development hingga produksi. Ini menghilangkan masalah "works on my machine" yang sering dihadapi developer.

Virtual Machine vs Container

Dalam dunia pengembangan dan pengoperasian aplikasi, dua teknologi yang sering dibanding-bandingkan adalah Virtual Machine (VM) dan Container. Kedua teknologi ini memiliki kelebihan dan kekurangannya masing-masing, tergantung pada kebutuhan spesifik proyek atau organisasi Anda.

Virtual Machine: Apartemen Pribadi di Dunia Komputasi

Virtual Machine, atau VM, adalah emulasi dari sebuah komputer sistem. Setiap VM berjalan di atas fisik hardware tetapi terisolasi dari hardware tersebut dan VM lainnya, berkat layer yang disebut Hypervisor. Hypervisor bertindak seperti manajer gedung apartemen, yang memastikan setiap "apartemen" (VM) memiliki sumber daya yang dibutuhkan dan tidak mengganggu penghuni lain.

  • Kekurangan VM:
    • Penggunaan Sumber Daya: Karena setiap VM membutuhkan sistem operasi lengkap, mereka cenderung menggunakan lebih banyak sumber daya.
    • Startup Lambat: Memulai sebuah VM bisa memakan waktu karena harus mem-boot sistem operasi sepenuhnya.

Container: Berbagi Sumber Daya dengan Efisien

Container, di sisi lain, membagi sistem operasi yang sama dan menjalankan aplikasi beserta dependensinya dalam paket yang terisolasi. Ini seperti tinggal di kost-kostan, di mana kamu membagi beberapa fasilitas utama dengan penghuni lain tetapi memiliki ruang pribadi kamu sendiri.

  • Kelebihan Container:
    • Efisiensi Sumber Daya: Karena container berbagi kernel OS, mereka jauh lebih ringan daripada VM dan menggunakan sumber daya yang lebih sedikit.
    • Startup Cepat: Container dapat dimulai dalam hitungan detik, membuatnya ideal untuk skala aplikasi secara dinamis.
    • Portabilitas: Aplikasi dalam container dapat dengan mudah dijalankan di lingkungan apa pun tanpa perlu menyesuaikan.

Docker Overview

Definisi Docker

Mengapa Docker Itu Penting?

Nah, sebelum kita masuk ke teknisnya, mari kita bahas dulu kenapa sih Docker ini penting banget buat kita yang berkecimpung di dunia pengembangan software. Jadi, Docker ini menyediakan solusi untuk masalah klasik yang sering ditemui developer: "Aplikasi saya jalan dengan sempurna di komputer saya, kok pas di tempat lain malah error, ya?"

Docker datang sebagai penyelamat dengan konsep kontainerisasi. Bayangin, aplikasi kita dengan semua kebutuhan dan ketergantungannya dibungkus dengan rapi dalam sebuah kontainer. Kontainer ini bisa dijalankan di mana saja, mulai dari komputer pribadi kita, server di kantor, sampai ke server cloud yang jauh di sana. Singkatnya, Docker memastikan bahwa "It works on my machine" bisa berubah jadi "It works everywhere".

Docker telah mengubah cara kita mengembangkan, mengirimkan, dan menjalankan aplikasi dengan memberikan solusi kontainerisasi yang efisien. Untuk memahami bagaimana Docker dapat melakukan ini, penting untuk mengenal arsitektur dasar Docker dan komponen-komponen utamanya.

Docker Architecture

Arsitektur Docker terdiri dari beberapa komponen utama yang bekerja bersama untuk memungkinkan pembuatan, penjalanan, dan distribusi kontainer.

Docker Daemon

Docker Daemon (dockerd) adalah proses background yang mengelola objek-objek Docker seperti kontainer, gambar (images), jaringan, dan volume. Daemon Docker menerima perintah dari Docker Client melalui CLI atau REST API, mengelola operasi Docker, dan berkomunikasi dengan daemon lain untuk mengelola layanan Docker.

Docker Client

Docker Client (docker) adalah cara utama pengguna berinteraksi dengan Docker. Ketika Anda menggunakan perintah seperti docker run atau docker build, Docker Client mengirimkan perintah ini ke Docker Daemon, yang kemudian menjalankannya. Client Docker dapat berkomunikasi dengan lebih dari satu daemon.

Docker Registry

Docker Registry menyimpan Docker images. Docker Hub adalah registry publik yang paling dikenal dan digunakan untuk berbagi gambar secara luas. Namun, pengguna juga dapat menjalankan registry pribadi mereka sendiri. Ketika Anda menggunakan perintah docker pull atau docker push, images diambil atau dikirim ke registry yang ditentukan.

Cara Kerja Docker

  1. Inisiasi Dockerfile: Pengguna mendefinisikan Dockerfile yang memuat instruksi tentang cara membangun image.
  2. Build: Docker Client memberitahu Docker Daemon untuk membangun image dari Dockerfile.
  3. Penyimpanan: Image yang dibangun disimpan di Docker Registry untuk distribusi.
  4. Pull: Pengguna atau sistem lain dapat menarik images dari registry untuk digunakan.
  5. Eksekusi: Docker Daemon mengambil images dan menjalankan kontainer berdasarkan images tersebut.

Building Dockerfile

Bayangin kamu mau bikin kue. Apa yang kamu butuh? Resep dong. Nah, dalam dunia Docker, resep untuk membuat aplikasi kamu itu namanya Dockerfile. Dockerfile ini kayak panduan step-by-step buat Docker dalam mengemas aplikasi kamu jadi satu paket lengkap yang siap dijalankan sebagai kontainer.

Apa Itu Dockerfile?

Dockerfile adalah sebuah file teks tanpa ekstensi yang berisi serangkaian instruksi untuk Docker tentang cara membangun sebuah Docker Image. Image yang dibangun ini nantinya bisa kamu gunakan untuk menjalankan aplikasi kamu di lingkungan apa pun.

Komponen Utama Dockerfile

Dockerfile terdiri dari berbagai instruksi yang dimengerti oleh Docker, seperti:

  • FROM: Memulai dengan menentukan base image. Misal, FROM ubuntu:18.04 berarti kamu mulai dengan image Ubuntu versi 18.04 sebagai dasar.
  • WORKDIR: Mengatur direktori kerja di dalam image. Contoh, WORKDIR /app akan membuat direktori /app dan menjadikannya sebagai direktori kerja.
  • COPY atau ADD: Menyalin file dan direktori dari komputer kamu ke dalam image. COPY . /app berarti menyalin semua file di direktori saat ini ke dalam /app di image.
  • RUN: Menjalankan perintah saat membangun image. Ini bisa untuk menginstal paket, membuat file, atau seting lainnya. Misal, RUN apt-get update && apt-get install -y git.
  • CMD: Menentukan perintah default yang dijalankan saat kontainer di-start. Contoh, CMD ["python", "app.py"] akan menjalankan app.py dengan Python.

Contoh Dockerfile Sederhana

Misalnya, kamu ingin membuat aplikasi web Python sederhana:

# Pilih base image
FROM python:3.8

# Set direktori kerja
WORKDIR /app

# Salin semua file ke dalam image
COPY . .

# Instal dependencies
RUN pip install -r requirements.txt

# Tentukan perintah yang dijalankan saat kontainer start
CMD ["python", "./app.py"]

Setelah Dockerfile kamu siap, kamu bisa membangun Docker Image dengan perintah:

docker build -t nama-aplikasi-kamu .

Tanda titik . di akhir berarti Docker akan mencari Dockerfile di direktori saat ini.

Environment Variables

Dalam pengembangan aplikasi, sering kali kita butuh cara yang fleksibel untuk mengkonfigurasi aplikasi tergantung lingkungan tempat aplikasi itu dijalankan. Misalnya, setting database di lingkungan development bisa berbeda dengan di production. Nah, di sinilah keajaiban variabel lingkungan atau Environment Variables berperan dalam Docker.

Apa Itu Environment Variables?

Environment Variables adalah variabel yang dapat digunakan untuk menyetel konfigurasi yang bisa berubah-ubah dalam aplikasi tanpa harus mengubah kode. Dalam konteks Docker, environment variables bisa sangat berguna untuk menyesuaikan perilaku kontainer saat runtime, memudahkan konfigurasi aplikasi di berbagai lingkungan.

Menggunakan Environment Variables

Kamu bisa menentukan environment variables saat menjalankan kontainer dengan perintah docker run menggunakan flag -e atau --env:

docker run -d -e "DATABASE_URL=jdbc:mysql://localhost:3306/mydb" my_web_app

Docker Images

Docker Image adalah template baca-saja yang berisi instruksi untuk membuat kontainer Docker. Images digunakan untuk menyimpan dan mengirimkan aplikasi dan lingkungan eksekusinya. Anda dapat membangun images sendiri atau menggunakan images yang dibuat oleh orang lain dan dihosting di registry.

Bayangin ini kayak blueprint atau resep dari aplikasi kita. Semua yang perlu ada di dalam kontainer, termasuk aplikasi dan lingkungannya, ada di sini.

Mengapa Docker Image itu Penting?

Coba bayangkan, kamu punya aplikasi yang ingin dijalankan di berbagai lingkungan, dari laptop pribadi, server di kantor, hingga cloud. Docker Image inilah yang memastikan aplikasi kamu bisa berjalan konsisten di semua tempat itu tanpa hambatan. Ia membungkus aplikasi kamu beserta semua yang dibutuhkan aplikasi itu untuk berjalan: kode aplikasi, runtime, library, variabel lingkungan, dan file konfigurasi lainnya. Semacam koper siap pakai yang tinggal dibawa ke mana saja.

Docker Containers

Setelah kita ngomongin tentang Docker Images sebagai blueprint, sekarang kita masuk ke jantungnya Docker: Kontainer. Bayangin Docker Image itu seperti cetakan kue, sedangkan Docker Container itu kuenya sendiri. Kontainer adalah instansi nyata yang berjalan dari sebuah image, yang bisa kamu lihat, sentuh, dan tentu saja, jalankan aplikasi kamu di dalamnya.

Apa Itu Docker Container?

Docker Container adalah paket software ringan, portabel, dan isolasi yang memungkinkan aplikasi untuk berjalan dengan cepat dan konsisten di berbagai lingkungan komputasi. Kontainer Docker mengemas aplikasi dan semua yang dibutuhkan untuk menjalankan aplikasi tersebut, termasuk sistem operasi, kode aplikasi, runtime, sistem perpustakaan, dan file konfigurasi.

Mengelola Kontainer

Docker juga menyediakan berbagai perintah untuk mengelola kontainer, seperti:

  • docker ps: Menampilkan semua kontainer yang berjalan.
  • docker stop: Menghentikan kontainer yang sedang berjalan.
  • docker rm: Menghapus kontainer yang sudah berhenti.
  • docker logs: Melihat log dari kontainer yang berjalan.

Cgroups and Namespaces

Ketika kita berbicara tentang kontainer dan bagaimana mereka merevolusi cara kita mengembangkan, mengirimkan, dan menjalankan aplikasi, dua konsep penting yang harus kita pahami adalah Cgroups (Control Groups) dan Namespaces. Kedua mekanisme ini adalah fitur inti dari kernel Linux yang memungkinkan kontainerisasi bekerja dengan efisien dan aman.

Cgroups: Mengelola Sumber Daya

Cgroups, atau Control Groups, adalah fitur Linux yang memungkinkan pembagian dan pembatasan sumber daya sistem (seperti CPU, memori, bandwidth I/O) untuk sekelompok proses. Dengan Cgroups, kita bisa memastikan bahwa setiap kontainer hanya menggunakan bagian sumber daya yang telah ditentukan, mencegah satu kontainer dari mengambil sumber daya lebih dari yang seharusnya dan mempengaruhi kontainer atau proses lain pada sistem.

Namespaces: Isolasi Proses

Namespaces adalah fitur yang menyediakan isolasi untuk sekelompok proses, sehingga proses dalam satu namespace tidak bisa melihat atau berinteraksi dengan proses di namespace lain. Ini memungkinkan kita untuk menjalankan banyak kontainer pada satu sistem host tanpa kontainer tersebut saling mengganggu. Namespaces membungkus setiap kontainer dalam "dinding" virtualnya sendiri, menjaga isolasi lingkungan operasi.

  • Jenis-Jenis Namespaces Utama:
    • PID Namespace: Isolasi ID proses, memungkinkan setiap kontainer memiliki proses dengan PID 1 dan seterusnya.
    • Network Namespace: Isolasi stack jaringan, memungkinkan setiap kontainer memiliki tampilan jaringan sendiri, termasuk alamat IP dan routing table.
    • Mount Namespace: Isolasi filesystem, memungkinkan setiap kontainer memiliki filesystem root sendiri.
    • Dan lainnya, seperti User, UTS, IPC, dan Cgroup Namespace.

Docker Network

Saat kita ngomongin kontainer dan aplikasi yang berjalan di dalamnya, nggak bisa lepas dari yang namanya jaringan atau network. Docker Network ini adalah fitur keren dari Docker yang memungkinkan kontainer-kontainer untuk berkomunikasi satu sama lain dan juga dengan dunia luar. Mirip seperti jaringan sosial tapi buat kontainer, gitu deh.

Kenapa Docker Network itu Penting?

Bayangin kalau setiap kontainer itu orang di suatu acara. Tanpa adanya jaringan, mereka bakal kesulitan berkomunikasi. Docker Network memastikan semua "orang" (baca: kontainer) ini bisa ngobrol dan berinteraksi dengan lancar, baik di dalam satu "ruangan" (host) maupun antar "ruangan" (host).

Docker Volumes

Ketika kita ngobrolin tentang Docker dan kontainer-kontainer kecenya, ada satu pertanyaan yang sering muncul: "Gimana sih cara kita nyimpen data yang bisa bertahan meskipun kontainernya udah dihapus?" Nah, jawabannya ada pada Docker Volumes.

Apa Itu Docker Volumes?

Docker Volumes adalah mekanisme yang disediakan oleh Docker untuk menyimpan atau membagikan data di antara kontainer-kontainer atau antara host dan kontainer. Volume ini diatur oleh Docker Daemon dan terpisah dari siklus hidup kontainer itu sendiri. Artinya, data yang kamu simpan di volume bakal tetap ada meski kontainer sudah lenyap.

Kenapa Pakai Docker Volumes?

  • Persistensi Data: Data penting seperti database atau file konfigurasi aplikasi perlu bertahan meski kontainer di-restart atau dihapus. Docker Volumes memastikan data tersebut aman.
  • Berbagi Data: Kamu bisa menggunakan volume untuk berbagi data antar kontainer atau antara host dan kontainer, memudahkan proses development dan testing.
  • Efisiensi: Dengan volume, read dan write operasi lebih cepat dibandingkan menyimpan data di layers file system kontainer.

Cara Kerja Docker Volumes

Saat kamu membuat volume dengan Docker, Docker Daemon akan menyimpan volume tersebut di dalam host filesystem tetapi di luar filesystem kontainer. Kamu bisa menentukan pathnya sendiri atau membiarkan Docker yang mengatur lokasinya.

Docker Hands-On

Pre-Requisite

My Personal Host Spesification

            .-/+oossssoo+/-.               raflihadiana@Kamado
        `:+ssssssssssssssssss+:`           -------------------
      -+ssssssssssssssssssyyssss+-         OS: Ubuntu 22.04.2 LTS on Windows 10 x86_64
    .ossssssssssssssssssdMMMNysssso.       Kernel: 5.15.133.1-microsoft-standard-WSL2
   /ssssssssssshdmmNNmmyNMMMMhssssss/      Uptime: 12 hours, 20 mins
  +ssssssssshmydMMMMMMMNddddyssssssss+     Packages: 723 (dpkg), 6 (snap)
 /sssssssshNMMMyhhyyyyhmNMMMNhssssssss/    Shell: bash 5.1.16
.ssssssssdMMMNhsssssssssshNMMMdssssssss.   Theme: Adwaita [GTK3]
+sssshhhyNMMNyssssssssssssyNMMMysssssss+   Icons: Adwaita [GTK3]
ossyNMMMNyMMhsssssssssssssshmmmhssssssso   Terminal: Windows Terminal
ossyNMMMNyMMhsssssssssssssshmmmhssssssso   CPU: AMD Ryzen 5 4600H with Radeon Graphics (12) @ 2.994GHz
+sssshhhyNMMNyssssssssssssyNMMMysssssss+   GPU: 4e65:00:00.0 Microsoft Corporation Device 008e
.ssssssssdMMMNhsssssssssshNMMMdssssssss.   Memory: 1158MiB / 3601MiB
 /sssssssshNMMMyhhyyyyhdNMMMNhssssssss/
  +sssssssssdmydMMMMMMMMddddyssssssss+
   /ssssssssssshdmNNNNmyNMMMMhssssss/
    .ossssssssssssssssssdMMMNysssso.
      -+sssssssssssssssssyyyssss+-
        `:+ssssssssssssssssss+:`
            .-/+oossssoo+/-.

You need to install Docker based on your Host OS. Then install gcloud client for accessing the Google Cloud Service Provider troughout terminal.

Docker Container

  1. Install Docker Engine
  • Set up Docker's apt repository
    ​​​​# Add Docker's official GPG key:
    ​​​​sudo apt-get update
    ​​​​sudo apt-get install ca-certificates curl
    ​​​​sudo install -m 0755 -d /etc/apt/keyrings
    ​​​​sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
    ​​​​sudo chmod a+r /etc/apt/keyrings/docker.asc
    
    ​​​​# Add the repository to Apt sources:
    ​​​​echo \
    ​​​​  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
    ​​​​  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
    ​​​​  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    ​​​​sudo apt-get update
    
  • Install the Docker packages
    ​​​​sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    
  • Post install to run without sudo
    ​​​​sudo groupadd docker
    
    ​​​​sudo usermod -aG docker $USER
    
    ​​​​newgrp docker
    
    ​​​​docker run hello-world
    

Google Cloud CLI

  1. Install Google Cloud CLI

    Installation Link: https://cloud.google.com/sdk/docs/install

  • Download the binary by curl

    ​​​​curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-463.0.0-linux-x86_64.tar.gz
    
  • Extract the binary to be output /google-cloud-sdk

    ​​​​tar -xf google-cloud-cli-463.0.0-linux-x86_64.tar.gz
    
  • Execute the script

    ​​​​./google-cloud-sdk/install.sh
    
  • Start the project inisialization

    ​​​​./google-cloud-sdk/bin/gcloud init
    
    Expected Output
    ​​​​Your browser has been opened to visit: ​​​​https://accounts.google.com/o/oauth2/...
    ​​​​Pick cloud project to use: ​​​​ [1] boot-camp-gdsc
    ​​​​Your Google Cloud SDK is configured and ready to use!

Working with Docker

In this demo we'll cover two application example to use.

1. Supabase Backend Application

This APIs was developed using:

  • Node.Js v18.13.0
  • Express v4.18.2
  • Supabase

How to run this APIs manually

  • Clone this project to your GCP project’s repository

    ​​​​git clone https://github.com/hiskandaryps/express-example-app
    
  • Install all the required depedencies

    ​​​​npm install
    
  • Provide the required data for the .env file, that consist of : SUPABASE_URL, SUPABASE_KEY, PORT

    ​​​​cp .env.example .env
    

    Here's the value for the .env

    ​​​​PORT=3000 ​​​​VERSION=v1 ​​​​SUPABASE_URL=https://bwstuipaunilvlgodbzq.supabase.co ​​​​SUPABASE_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJ3c3R1aXBhdW5pbHZsZ29kYnpxIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDY3OTg0MjEsImV4cCI6MjAyMjM3NDQyMX0.dDRT8SkJho2JYSuK0DGbW1drdybzZp7Nf88SU3kK96A
  • Run the back-end application

    ​​​​npm start
    

How to run Dockerize the App

  1. Create Dockerfile to build the image

    • Initialize the file

      ​​​​​​​​cd express-example-app
      ​​​​​​​​touch Dockerfile
      
    • Configure the Dockerfile align with API Spec

      ​​​​​​​​FROM node:18-alpine ​​​​​​​​WORKDIR /opt/app ​​​​​​​​COPY . . ​​​​​​​​RUN npm install ​​​​​​​​EXPOSE 3000 ​​​​​​​​CMD [ "npm", "start"]
    • Create a file called .dockerignore

      ​​​​​​​​.idea
      ​​​​​​​​.gitignore
      ​​​​​​​​node_modules/
      
    • Build the image

      ​​​​​​​​docker build -t gdsc/test .
      
  2. Run the custom application image

    • Run the image with customized port to expose
      ​​​​​​​​docker run -p 8080:4000 -d gdsc/test
      
    • Validate if the containner is running with docker ps
      ​​​​​​​​CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                       NAMES
      ​​​​​​​​20d00bcf7d9d   gdsc/test      "docker-entrypoint.s…"   16 minutes ago   Up 16 minutes   0.0.0.0:8080->3000/tcp, :::8080->3000/tcp   laughing_margulis
      
    • Validate by Postman testing
      image

2. PostgreSQL Backend Application

This APIs was developed using:

  • Node.Js v18.13.0
  • Express v4.18.2
  • PostgreSQL

How to run this APIs manually

  • Clone this project to your GCP project’s repository

    ​​​​git clone https://github.com/raflihadiana/nodejs-example-app
    ​​​​cd nodejs-example-app/src
    
  • Install all the required depedencies

    ​​​​npm install
    
  • Start a PostgreSQL databases and create the tables

    ​​​​docker run -it -e "POSTGRES_HOST_AUTH_METHOD=trust" -p 5432:5432 postgres
    ​​​​npm run migrate
    
  • Run the back-end application

    ​​​​npm start
    

How to run Dockerize the App

  1. Create Dockerfile to build the image

    • Initialize the file

      ​​​​​​​​cd nodejs-example-app
      ​​​​​​​​touch Dockerfile
      
    • Configure the Dockerfile align with API Spec

      ​​​​​​​​FROM node:18.16.0-alpine3.17 ​​​​​​​​RUN mkdir -p /opt/app ​​​​​​​​WORKDIR /opt/app ​​​​​​​​COPY src/package.json src/package-lock.json . ​​​​​​​​RUN npm install ​​​​​​​​COPY src/ . ​​​​​​​​EXPOSE 3000 ​​​​​​​​CMD [ "npm", "start"]
    • Create a file called .dockerignore

      ​​​​​​​​.git
      ​​​​​​​​.gitignore
      ​​​​​​​​src/node_modules/
      
    • Build the image

      ​​​​​​​​docker build -t addressbook .
      
  2. Run the custom application image

    • Run the image with customized port to expose

      ​​​​​​​​docker run -it -p 3000:3000 addressbook
      
    • Run the image with docker compose for network & DB Configuration

      ​​​​​​​​# docker-compose.yml
      
      ​​​​​​​​version: "3.9"
      ​​​​​​​​services:
      ​​​​​​​​  postgres:
      ​​​​​​​​    image: postgres:latest
      ​​​​​​​​    environment:
      ​​​​​​​​      POSTGRES_USER: postgres
      ​​​​​​​​      POSTGRES_PASSWORD: postgres
      ​​​​​​​​    ports: 
      ​​​​​​​​      - '5432:5432'
      ​​​​​​​​    volumes:
      ​​​​​​​​      - addressbook-db:/var/lib/postgresql/data
      
      ​​​​​​​​  addressbook:
      ​​​​​​​​    build:
      ​​​​​​​​      context: .
      ​​​​​​​​    environment:
      ​​​​​​​​      DB_SCHEMA: postgres
      ​​​​​​​​      DB_USER: postgres
      ​​​​​​​​      DB_PASSWORD: postgres
      ​​​​​​​​      DB_HOST: postgres
      ​​​​​​​​    depends_on:
      ​​​​​​​​      - postgres
      ​​​​​​​​    ports:
      ​​​​​​​​      - '3000:3000'
      
      ​​​​​​​​volumes:
      ​​​​​​​​  addressbook-db:
      
      ​​​​​​​​docker compose run addressbook npm run migrate
      
      ​​​​​​​​docker compose up --build
      
    • Validate by Postman testing
      image

    • If you want to stop the container

      ​​​​​​​​docker compose down
      

Push to Registries

Docker Hub Registry

  1. Push the Image to Dockerhub

    • Login in the terminal to your Docker Account

      ​​​​​​​​docker login
      
    • Change the Docker Image tag align with Dockerhub Repository

      ​​​​​​​​docker tag gdsc/test raflihadiana/gdsc:test
      
    • Push to the Default Registry Dockerhub

      ​​​​​​​​docker push raflihadiana/gdsc:test
      
      Expected Output
      ​​​​​​​​The push refers to repository [docker.io/raflihadiana/gdsc]
      ​​​​​​​​def9ba6d524e: Pushed
      ​​​​​​​​295b4b0b0a9e: Pushed
      ​​​​​​​​a75f8c5b7682: Pushed
      ​​​​​​​​b325b33b9813: Pushed
      ​​​​​​​​4a0d315ad53e: Pushed
      ​​​​​​​​29e213bad130: Pushed
      ​​​​​​​​d4fc045c9e3a: Pushed
      ​​​​​​​​test: digest: sha256:1d9dd48767e5d9351cbbbae9236cda8c57e87586a7b1569e339c0a6db8e30b6f size: 1786
      

      image

GCP Artifact Repository

  1. Push the Image to GCP Artifact Repository

    • Go to your Google Cloud Console then Create a repository for your image
      Test

    • Copy this path as the configured location server
      testt

      Mine is asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2

    • Authenticate yourself in CLI for Registry Access

      ​​​​​​​​gcloud auth asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2
      
    • Change your local image tag to your image domain path

      ​​​​​​​​docker tag gdsc/test asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2:test
      
    • Push your image to configured location repository path

      ​​​​​​​​docker push asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2:test
      
      Expected Output
      ​​​​​​​​The push refers to repository [asia-southeast2-docker.pkg.dev/boot-camp-gdsc/gdsc-cc2/version]
      ​​​​​​​​def9ba6d524e: Pushed
      ​​​​​​​​295b4b0b0a9e: Pushed
      ​​​​​​​​a75f8c5b7682: Pushed
      ​​​​​​​​b325b33b9813: Pushed
      ​​​​​​​​4a0d315ad53e: Pushed
      ​​​​​​​​29e213bad130: Pushed
      ​​​​​​​​d4fc045c9e3a: Pushed
      ​​​​​​​​test: digest: sha256:1d9dd48767e5d9351cbbbae9236cda8c57e87586a7b1569e339c0a6db8e30b6f size: 1786
      
    • Validate the pushed image in your Artifact Registry Console
      image

Troubleshoot

  1. Docker Credentials Error

    Error Statement:

    image

    ​​​​Error saving credentials: error storing credentials – err: exec: “docker-credential-desktop”: executable file not found in $PATH, out:
    
    Solution

    There are several ways to resolve this issue. One easiest way would be making any of the following changes in ~/.docker/config.json file.

    • Replace “credsStore” by “credStore” as many people suggest in other blogs.
    • Replace “credsStore” by any value.
    • Remove “credsStore” property from the config.

    For more detail solution you can check it here.