dyanzzz / docker-workshop

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Docker (dan Kubernetes) untuk Pemula

Salah satu yang menarik dari docker adalah dukungan komunitas yang sangat kuat. Docker bahkan menjadi standar dalam deployment kubernetes (kita akan membahas kubernetes di bagian selanjutnya).

Dalam repo ini, saya akan menunjukkan contoh pemanfaatan docker secara nyata. Pada repo ini kita akan membangun aplikasi "notepad" online seperti ini menggunakan redis dan node-js.

Perlu diingat, bahwa redis umumnya dipakai untuk caching, sehingga tidak cocok untuk dijadikan penyimpanan permanen. Jika teman-teman berminat mengembangkan aplikasi ini lebih lanjut, silahkan menggunakan mysql, mongo atau database engine lain.

Yang kita butuhkan

  • docker
  • docker-compose
  • node-js & npm
  • kubectl
  • akun docker-hub
  • akun okteto
  • ketekunan dan kemauan untuk belajar :)

Catatan:

  • Saya menggunakan ubuntu-WSL dalam windows
  • Untuk menginstall docker di windows, kalian harus menggunakan windows 10 pro dengan hyper-v yang telah diaktifkan
  • Ikuti panduan ini untuk mengakses docker-for-windows dari dalam WSL
  • Atau gunakan linux :)

Apa itu Docker? Apa Bedanya dengan Virtual Machine?

Docker adalah platform virtualisasi di level OS. Docker biasa dipakai untuk membuat container.

Container sendiri adalah paket software yang terisolasi (saling lepas satu sama lain). Adapun isolasi yang dilakukan hanya di level aplikasi saja. Dengan demikian satu container dan container lain masih bisa berbagi kernel yang sama. Sifat kernel-sharing inilah yang membedakan docker-container dengan virtual machine.

Docker

Docker melakukan virtualisasi di level aplikasi, sehingga semua container di satu mesin memakai kernel OS yang sama.

Jika kalian memakai linux, maka docker-container kalian akan memakai kernel yang sama dengan OS utama. Sebaliknya, jika teman-teman menggunakan windows/mac, maka akan ada level virtualisasi tambahan untuk emulasi kernel linux.

Virtual Machine

Virtual machine melakukan virtualisasi di level hardware, sehingga antar VM menggunakan kernel, alokasi RAM, dan alokasi CPU yang berbeda. Akibatnya untuk membuat virtual-machine, kita diwajibkan membuat spesifikasi RAM dan CPU untuk setiap VM.

Instalasi docker

Ikuti panduan di situs resmi docker

Docker Image

Untuk membuat sebuah docker-container, kita perlu terlebih dahulu mendefinisikan spesifikasi-nya. Spesifikasi inilah yang kita kenal dengan sebutan docker-image.

Saat ini sudah ada banyak sekali docker-image siap pakai. Kalian bisa mengunjungi docker hub untuk mencari docker-image yang kalian butuhkan.

Kebetulan, docker-image untuk redis pun sudah tersedia dan siap dipakai.

Untuk men-download docker-image, kita bisa menggunakan perintah docker pull. Berikut contoh penggunaannya:

Pull Docker Image

docker image pull redis:latest

Kalian juga bisa melihat daftar docker-images yang tersedia di komputer lokal dengan menjalankan perintah

docker image ls

Tips: Biasanya perintah docker memiliki format seperti ini:

docker <entitas> <aksi> [opsi]

Jadi kalian bisa sedikit "asal tebak", tidak perlu menghafal semua perintah :)

Membuat Container Redis

Untuk membuat docker container dengan nama my-redis dari image redis:latest, kalian bisa menjalankan perintah berikut:

docker run --name my-redis -p 6379:6379 -d redis:latest

Ada beberapa parameter yang sering dipakai pada perintah docker run:

  • --name untuk setting nama container.
  • -p untuk port forwarding. Format yang dipakai adalah -p <host-port>:<container-port>. Jadi seandainya kita ingin port 6379 pada container kita bisa diakses melalui port 4000 pada localhost, maka kita bisa melakukan perintah ini: docker run --name my-redis -p 4000:6379 -d redis:latest.
  • -d untuk men-spesifikasikan nama image.
  • -e untuk setting environmant variable. Format yang digunakan adalah -e <nama-variable>=<isi-variable>. Untuk saat ini, belum ada environment yang perlu di set.
  • -v untuk membuat persistance volume di host. Format yang digunakan adalah -v <path-di-host>:<path-di-container>. Untuk saat ini, kita tidak akan menggunakan volume.

Catatan:

  • Jalankan docker start my-redis dan docker stop my-redis untuk menjalankan atau memberhentikan container my-redis.
  • Jalankan docker ps untuk melihat list container yang sedang berjalan.

Bermain dengan Redis (Bonus)

Pada dasarnya, redis banyak digunakan untuk caching. Redis menyimpan cache kita dalam RAM. Oleh sebab itu, io-access-time relatif lebih kecil daripada RDBMS seperti MySQL yang melakukan penyimpanan di harddisk.

Karena ini pula, sangat tidak disarankan untuk menggunakan redis sebagai media penyimpanan utama (seperti yang akan kita lakukan sebentar lagi... he3x).

Cache pada redis disimpan dengan format key-value. Jika pada komputer kalian terinstall redis-cli atau aplikasi redis-client lain, kalian bisa mencoba perintah-perintah berikut:

> set password rahasia
OK

> get password
"rahasia"

> keys *
1) "password"

> del password
(integer) 1

Membuat Web-app

Kembali ke tujuan awal yang sudak kita sepakati tadi, kita ingin membuat aplikasi notepad-online. Untuk kita membutuhkan sebuah web-application.

Coding web-application kita terletak di folder app dari repository ini.

Untuk menjalankannya, kalian bisa menuliskan perintah berikut:

cd app
npm install
node index

Aplikasi akan berjalan di port 3000. Kalian bisa mengaksesnya menggunakan alamat http://localhost:3000 pada browser.

Aplikasi yang sudah kita buat ini memiliki beberapa konfigurasi yang bisa diubah melalui environment variable.

Secara khusus perhatikan bagian kode ini:

    const httpPort = process.env.HTTP_PORT || 3000;
    const redisHost = process.env.REDIS_HOST || 'localhost';
    const redisPort = parseInt(process.env.REDIS_PORT || '6379', 10);

Ketiga baris itu memungkinkan kalian bisa mengubah isi variable httpPort, redisHost, dan redisPort tanpa mengubah kode sama sekali.

Untuk mencobanya, coba lakukan perintah berikut

HTTP_PORT=4000 node index

Membuat Dockerfile untuk Web-app

Nah, sekarang kita ingin meng-kontainer kan aplikasi kita. Untuk melakukan ini, kita bisa harus terlebih dahulu mendefinisikan spesifikasi docker-image.

Spesifikasi docker-image biasanya disimpan pada file Dockerfile.

Berikut isi Dockerfile untuk Web-app kita:

# image kita adalah turunan dari node:latest
FROM node:latest

# di sini kita mendefinisikan bahwa working directory di container adalah 
# /usr/src/app
WORKDIR /usr/src/app

# di sini kita meng-copy package.json dan package-lock.json ke 
# working directory container (./)
COPY package*.json ./

# setelah package.json dan package-lock.json ter-copy ke 
# working directory container, kita menjalankan npm install untuk 
# men-download library external ke container
RUN npm install

# terakhir, kita meng-copy semua source yang ada ke working directory container
COPY . .

# bagian ini sebenarnya tidak terlalu penting, hanya untuk dokumentasi saja, 
# supaya orang lain tahu bahwa aplikasi kita ter-expose di port 3000 
# tanpa perlu membuka source-code kita.
EXPOSE 3000

# untuk menjalankan aplikasi kita, perintah yang perlu dieksekusi adalah 
# "node index"
CMD [ "node", "index" ]

Memakai Docker-compose

Satu hal lagi yang menarik, kita bisa mem-bundle sejumlah docker-image supaya bisa didistribusikan dengan lebih mudah.

Dengan demikian, kalian hanya membutuhkan docker dan docker-compose untuk menjalankan aplikasi notepad-online kita. Kalian bahkan tidak perlu menginstall Node.js !!!

Berikut adalah docker-compose.yaml yang kita gunakan:

version: '2.0'
services:

  # web adalah alias untuk web-app kita
  web:
    build: ./app # aplikasi kita menggunakan Dockerfile di folder `./app`
    ports:
        - "8080:3000" # kalian bisa mengakses aplikasi kita melalui localhost:8080
    environment:
        - HTTP_PORT=3000
        - REDIS_PORT=6379
        - REDIS_HOST=redis # perhatikan, di sini kita menggunakan alias
    depends_on:
        - redis

  # redis adalah alias untuk redis container
  redis:
    image: redis:latest # untuk redis, kita akan menggunakan image redis:latest
    ports:
        - "6379:6379" # kalian bisa mengakses redis melalui localhost:6379

Untuk menjalankan docker-compose, kalian bisa menuliskan perintah docker-compose up

Setelah menjalankan docker-compose, kalian bisa coba menjalankan perintah docker ps.

Di sini kalian akan melihat bahwa nama container yang dibuat dengan menggunakan docker-compose adalah <nama-folder>_<service-name>.

Mempublikasi Docker-image

Bagaimana jika kita ingin mendistribusikan docker-image kita tanpa mendistribusikan source code?

Dalam kasus seperti itu, kita bisa mempublikasikan image kita ke docker-hub (atau registry lain).

Untuk itu, pertama-tama kalian harus memiliki akun di hub.docker.com.

Setelah memiliki akun di docker-hub, kalian perlu membuat repository. Dalam kasus ini, saya membuat repository gofrendi/notepad.

docker login
docker tag docker-workshop_web <user-name>/notepad
docker push <user-name>/notepad

Catatan: saat tulisan ini dibuat, ada bug pada package docker-compose ubuntu. Jika kalian menggunakan WSL-ubuntu, maka kalian bisa menjalankan perintah di atas dengan menggunakan power-shell.

Kini orang lain bisa membuat docker-compose sekalipun tak memiliki source-code kita:

version: '2.0'
services:

  web:
    image: gofrendi/notepad:latest
    ports:
        - "8080:3000"
    environment:
        - HTTP_PORT=3000
        - REDIS_PORT=6379
        - REDIS_HOST=redis
    depends_on:
        - redis

  redis:
    image: redis:latest
    ports:
        - "6379:6379"

Kubernetes

Kubernetes adalah container-orchestration-system. Secara sederhana, kubernetes memungkinkan kalian untuk melakukan scaling, restart service, dan deployment secara lebih mudah.

Dalam kesempatan ini kita belum akan membahas kubernetes secara terlalu detail.

Saat ini, salah satu penyedia layanan kubernetes yang cukup ramah pemula dan tidak perlu credit-card adalah okteto

Kalian bisa mencoba membuat akun di okteto, dan membuat namespace.

Usai membuat namespace, kalian bisa mendownload credential okteto-kube.config dan menjalankan perintah berikut:

export KUBECONFIG=./okteto-kube.config
kubectl get all
kubectl apply -f redis-k8s.yaml
kubectl apply -f notepad-k8s.yaml

Mari kita bahas sedikit tentang apa yang terjadi di sini.

Kubernetes sebenarnya bisa diakses melalui HTTP API, namun biasanya para developer lebih suka menggunakan program kubectl supaya bisa melakukan deployment dari terminal/console.

Dalam prakteknya, banyak perusahaan yang sudah memanfaatkan pipeline CI/CD (Continuous Integration/Continuous Deployment). Dengan adanya CI/CD ini, developer bisa melakukan deployment secara otomatis, bergantung pada aksi yang didefinisikan. Misalnya, seteiap kali merge ke branch master, atau setiap kali ada penambahan tag tertentu pada sebuat commit.

Pada kesempatan ini, kita tidak akan membahas CI/CD, kita hanya akan fokus pada deployment saja.

Autentikasi

Biasanya penyedia layanan kubernetes (GCP/AWS/Azure/Octeto/Digital Ocean, dsb) menyediakan file autentikasi yang perlu kita download di komputer lokal. kubectl mengenal file autentikasi ini berdasarkan environment variable KUBECONFIG.

Inilah yang kita lakukan di baris pertama:

export KUBECONFIG=./okteto-kube.config

Get All

Perintah kubectl get all biasa dipakai untuk melihat resource apa saja yang sudah ter-deploy ke cloud. Biasanya, kita juga menggunakan perintah ini untuk memastikan apakah kubectl di komputer kita sudah terhubung ke cloud.

Apply

Perintah kubectl apply berguna untuk men-deploy deployment/service dan artifact lain ke cloud.

Sedikit lebih dalam

Nah, mungkin muncul pertanyaan baru, apa itu deployment, dan apa itu service?

Sebenarnya di balik layar, kubernetes meng-orchestrate beberapa VM/komputer. VM/komputer ini kita kenal dengan sebutan node. Saat kita men-deploy sesuatu, maka kubernetes akan meletakkannya pada node-node yang masih memiliki kapasitas.

Dalam satu node, bisa terdapat banyak pod. Satu pod umumnya berisi satu docker-container (bisa lebih).

Sekarang bayangkan situs berita semacam kumparan, detik, atau tirto. Menurut kalian, situs-situs tersebut lebih sering dipakai untuk membaca berita, atau menulis berita?

Tentu saja, lebih banyak dipakai untuk membaca berita. Dalam hal ini kita bisa asumsikan bahwa pod untuk membaca data dan menampilkan ke user harus lebih banyak daripada pod untuk menuliskan berita (yang biasanya dipakai jurnalis).

Nah, supaya pod-pod tadi bisa berkoordinasi satu sama lain, dibutuhkan semacam gateway/load-balancer yang bertugas membagi beban kerja pod. Untuk itu, pod-pod tadi perlu dibungkus dalam satu service.

Pada contoh situs berita kita tadi, mungkin kita hanya memiliki 2 service saja, writer dan reader. Namun masing-masing service membungkus beberapa pod. Katakan saja, service writer membungkus 10 pod, sedangkan service reader membungkus 2 pod.

Mari kita lihat contoh deployment dan service.

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
    name: notepad
spec:
    replicas: 1 # di sini, kita hanya akan punya satu pod. Pada kenyataannya bisa dibuat auto-scale
    selector:
        matchLabels:
            app: notepad
    template:
        metadata:
            labels:
                app: notepad
        spec:
            containers: # sebenarnya bisa ada banyak container, tapi umumnya satu
                - image: gofrendi/notepad # nama docker image yang kita pakai
                  name: notepad # nama container
                  env: # environment variable
                      - name: HTTP_PORT
                        value: "3000"
                      - name: REDIS_PORT
                        value: "6379"
                      - name: REDIS_HOST
                        value: "redis" # ini me-refer ke service "redis"

Service

apiVersion: v1
kind: Service
metadata:
    name: notepad
    labels:
        app: notepad
    annotations:
        dev.okteto.com/auto-ingress: "true" # Ini supaya bisa diakses dari luar
spec:
    type: ClusterIP    
    ports: # daftar port yang akan kita forward ke pod.
        - name: notepad
          port: 3000
          targetPort: 3000
    selector:
        app: notepad

About


Languages

Language:JavaScript 83.1%Language:Dockerfile 16.9%