Docker Swarm adalah solusi clustering untuk Docker. Yang bisa membuat kita menjalankan Docker Container dalam mode HA (High Availability) dan mudah untuk skaling up/down pada beberapa server.
Alasan Menggunakan Docker Swarm
- Docker Swarm solusi clustering native untuk docker.
- Docker Swarm lebih mudah di setup/setting daripada Kubernetes.
- Docker Swarm jauh lebih hemat biaya untuk membuat Docker Container Cluster dibandingkan dengan Kubernetes.
Contoh Skenario
Dalam dokumentasi ini saya akan mencontohkan bagaimana setup High Availability Docker Swarm dengan skenario :
- Manager NODE, Karena untuk implementasi High Availability harus mempunyai minimal 3 manager-node jadi saya menyiapkan 3 pcs server fisik. Spesifikasi masing-masing server 4 CPU RAM 2GB.
- Load Balancer menggunakan Keepalived.
- Distributed Network Storage menggunakan GlusterFS.
Setup Docker Swarm Cluster
Install Docker, Docker Compose dan Git di setiap node sebelum inisialisasi docker swarm.
Inisialisasi Swarm Mode
Kemudian inisialisasi docker swarm di server node-master-1, login ssh dan jalankan perintah :
adam@master-1:~# sudo docker swarm init --advertise-addr 192.168.99.101
Dalam contoh di dokumentasi ini, sesuaikan --advertise-addr
dengan IP kita. Saya menggunakan IP 192.168.99.101 di node-master-1. Output yang muncul akan seperti ini :
Swarm initialized: current node (myjwx5z3m7kcrplih1yw0e2sy) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-2gwqttpup0hllec6p6xkun8nmht4xu18g09vsxyjhlyqc9sgjw-729yfmz5rfg02eiw0537m49c1 192.168.99.101:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
Setelah kita inisialisasi swarm mode, ada 2 perintah untuk menambahkan node manager atau node worker.
Join Manager
Karena kita hanya menggunakan 3 node sebagai master semua jadi jalankan kembali perintah berikut untuk mendapatkan join-token
sebagai manager yang akan kita jalankan di node-master-2 dan node-master-3.
adam@master-1:~# sudo docker swarm join-token manager
Setelah muncul perintah join-token
untuk manager, jalankan perintah di node-master-2 dan node-master-3 :
$ sudo docker swarm join --token SWMTKN-1-2gwqttpup0hllec6p6xkun8nmht4xu18g09vsxyjhlyqc9sgjw-eba5cbn1o4zv449w441bndfv0 192.168.99.101:2377
Join Worker
Untuk mendapatkan join-token
jika kita mempunyai node Worker, jalankan perintah seperti :
adam@master-1:~# sudo docker swarm join-token worker
Kemudian jalankan perintah join-token
yang muncul di server node worker kita.
Cek Daftar Member Node
Setelah kita menambahkan node-node, kita bisa cek member node swarm dengan menjalankan perintah pada salah satu node manager :
adam@master-1:~# sudo docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
yowshmeyvxwhu8kf979kn3gh6 * master-1 Ready Active Leader 25.0.2
rzn3rmbdkw1d6y9wmfm367u40 master-2 Ready Active Reachable 25.0.2
uolr8v5k5uipuqj81rmjdb8br master-3 Ready Active Reachable 25.0.2
Sampai sini kita sudah selesai setup docker swarm cluster setelah inisialilasi semua manager node.
Keepalived
Karena kita menerapkan High Availability Docker Swarm, dengan Keepalived kita bisa memungkinkan hanya menggunakan satu Virtual IP untuk mengakses semua services atau aplikasi dalam docker swarm, tanpa harus menargetkan ke IP masing-masing node. Keepalived dapat self-healing jika salah satu node mati, jadi IP selalu online untuk di akses oleh user.
Dalam contoh skenario ini, kita akan membuat 1 Virtual IP. IP Ini akan terarahkan ke salah satu node dan jika salah satu node mati, IP akan renegotiate routing otomatis ke node lain nya.
Contoh Layout:
- master-1 192.168.99.101
- master-2 192.168.99.102
- master-3 192.168.99.103
- Ingress (Virtual IP) – 192.168.99.100
Jadi user hanya mengakses 1 IP yaitu 192.168.99.100 untuk akses service atau aplikasi dalam container docker swarm kita.
Install
Jalankan perintah dibawah di semua node untuk menginstall Keepalived
$ sudo apt-get -y install keepalived
Setelah Keepalived terinstall di masing-masing node kita harus edit konfigurasi pada file /etc/keepalived/keepalived.conf
pada masing-masing node.
Edit Konfigurasi
Pada masing-masing node mempunyai konfigurasi berbeda untuk dapat provosioning.
node-master-1
adam@master-1:~# sudo nano /etc/keepalived/keepalived.conf
Kemudian isi dengan :
global_defs {
router_id DOCKER_INGRESS
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass passwordkita
}
virtual_ipaddress {
192.168.99.100
}
}
Aktifkan service Keepalived pada node :
adam@master-1:~# systemctl start keepalived
adam@master-1:~# systemctl enable keepalived
node-master-2
adam@master-2:~# sudo nano /etc/keepalived/keepalived.conf
Isi file konfigurasi :
global_defs {
router_id DOCKER_INGRESS
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass passwordkita
}
virtual_ipaddress {
192.168.99.100
}
}
Aktifkan service Keepalived pada node :
adam@master-2:~# systemctl start keepalived
adam@master-2:~# systemctl enable keepalived
node-master-3
adam@master-3:~# sudo nano /etc/keepalived/keepalived.conf
Isi file konfigurasi :
global_defs {
router_id DOCKER_INGRESS
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 80
advert_int 1
authentication {
auth_type PASS
auth_pass passwordkita
}
virtual_ipaddress {
192.168.99.100
}
}
Aktifkan service Keepalived pada node :
adam@master-3:~# systemctl start keepalived
adam@master-3:~# systemctl enable keepalived
Setelah konfigurasi keepalived di masing-masing node, kita bisa cek Virtual IP yang sudah kita tambahkan dengan menjalankan perintah di node-master-1 :
adam@master-1:~# ip a show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether fe:c3:8b:c2:b3:5a brd ff:ff:ff:ff:ff:ff
inet 192.168.99.101/24 brd 192.168.99.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.99.100/32 scope global eth0
valid_lft forever preferred_lft forever
Jika keepalived berhasil negotiate virtual ip di noce kita, kita bisa lihat terdapat IP 192.168.99.100 di interface eth0. Kita bisa coba ping IP tersebut di luar jaringan cluster kita.
GlusterFS
Karena kita mengimplementasikan High Availability Docker Swarm, jadi kita membutuhkan distributed file system yang bisa kita gunakan untuk menyimpan dan akses file di semua node. Menjaga high availability / data redundancy dengan konsep replikasi data otomatis dan mendistribusikan data di beberapa node berbeda. Pada contoh skenario ini saya menggunakan GlusterFS.
Di setiap node saya mempunyai Harddisk/SSD dengan kapasitas yang sama di khususkan untuk digunakan oleh Storage GlusterFS, dan saya menggunakan mode replikasi untuk replikasi data di semua node untuk kebutuhan Persistent Storage yang digunakan oleh container-container yang terdapat di docker swarm untuk menghindari single-point failure untuk penyimpanan data container.
Hostname
Saya menggunakan hostname agar Node/Peer GlusterFS dapat berkomunikasi, jadi saya edit /etc/hosts di semua node :
$ sudo nano /etc/hosts
192.168.99.101 master-1
192.168.99.102 master-2
192.168.99.103 master-3
Tinggal sesuaikan IP & hostname node swarm kita.
Install
Install GlusterFS di semua node dengan perintah :
$ sudo apt-get -y install glusterfs-server
$ sudo systemctl start glusterd
$ sudo systemctl enable glusterd
Persiapan Storage Volume
Di semua node kita buat Bricks untuk digunakan nantinya untuk membuat GlusterFS Volume. Bricks digunakan untuk menyimpan data asli di setiap server dan dianggap storage fisik dari GlusterFS volume.
Bricks
Di semua node yang terdapat harddisk, jalankan perintah berikut :
adam@master-1:~# fdisk -l
Disk /dev/ram0: 4 MiB, 4194304 bytes, 8192 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
.
.
.
Disk /dev/sda: 465.76 GiB, 500107862016 bytes, 976773168 sectors
Disk model: Samsung SSD 870
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Jika kita lihat saya mempunyai Samsung SSD dengan kapasitas 500GB, jadi kita gunakan /dev/sda
sebagai bricks di node-master-1.
# Format disk kita
adam@master-1:~# mkfs.xfs -f /dev/sda
# Buat lokasi folder untuk mounting ssd
adam@master-1:~# mkdir -p /mnt/ssd
# Tambahkan baris perintah ke /etc/fstab agar mount otomatis ssd saat booting
adam@master-1:~# echo "/dev/sda /mnt/ssd xfs defaults 0 0" | tee -a /etc/fstab
# Buat lokasi folder u/ dijadikan brick
adam@master-1:~# mkdir -p /mnt/ssd/glusterfs
# Mount
adam@master-1:~# mount -a
# Cek
adam@master-1:~# df -h /mnt/ssd/glusterfs
Lakukan hal yang sama di node-master-2 & node-master-3
Join Cluster
Join node-master-2 & node-master-3 ke cluster GlusterFS
adam@master-1:~# sudo gluster peer probe master-2
peer probe: success
adam@master-1:~# sudo gluster peer probe master-3
peer probe: success
# Check
adam@master-1:~# sudo gluster pool list
UUID Hostname State
2554d571-31ec-48f7-b049-f019efed7a14 master-2 Connected
821bbeba-e992-4d68-82c3-a8736e661b2b master-3 Connected
bf7d20c5-7787-48f5-86ab-2c6abb394cc0 localhost Connected
Kita bisa lihat semua node sudah join ke dalam glusterfs cluster.
Volume
Di GlusterFS, logical volume dibuat dari satu atau beberapa bricks (resource storage fisik). GlusterFS Volume adalah Storage Pool yang bisa di akses di beberapa node dalam cluster untuk menyimpan data. Di contoh skenario ini saya akan me replika 3 bricks semua node dengan mode Replicated dengan nama volume gfs0
.
adam@master-1:~# sudo gluster volume create gfs0 replica 3 transport tcp master-1:/mnt/ssd/glusterfs master-2:/mnt/ssd/glusterfs master-3:/mnt/ssd/glusterfs
Cek volume yang kita buat dengan perintah :
adam@master-1:~# sudo gluster volume info gfs0
Volume Name: gfs0
Type: Replicate
Volume ID: e457ca40-026c-4ac0-8c50-14bdab3cadc3
Status: Started
Snapshot Count: 0
Number of Bricks: 1 x 3 = 3
Transport-type: tcp
Bricks:
Brick1: master-1:/mnt/ssd/glusterfs
Brick2: master-2:/mnt/ssd/glusterfs
Brick3: master-3:/mnt/ssd/glusterfs
Options Reconfigured:
cluster.granular-entry-heal: on
storage.fips-mode-rchecksum: on
transport.address-family: inet
nfs.disable: on
performance.client-io-threads: off
Start volume dengan perintah :
adam@master-1:~# sudo gluster volume start gfs0
Sekarang kita sudah mempunyai GlusterFS Volume, kita tinggal mount di semua node dalam cluster dengan jalankan perintah :
$ mkdir -p /mnt/docker
$ echo "localhost:/gfs0 /mnt/docker glusterfs defaults,_netdev 0 0" | sudo tee -a /etc/fstab
$ mount -a
Folder /mnt/docker
adalah folder mounting volume glusterfs kita, dan sekarang kita sudah mempunyai persistent storage untuk docker container dengan kemampuan high availability dan redudancy.
Portainer
Tahap terakhir ya kita mulai deploy aplikasi di container docker swarm kita. Di sini saya coba mulai dengan deploy docker stack Portainer dalam cluster docker swarm, ya tentu saya kita gunakan nantinya untuk manage clustering kita.
Deploy
Buat docker-compose YAML.
$ nano portainer-agent-stack.yml
Dengan docker stack untuk deploy Portainer WebUI di salah satu manager node dan Portainer Agent di semua node
version: '3.2'
services:
agent:
image: portainer/agent:alpine
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
networks:
- agent_network
deploy:
mode: global
placement:
constraints: [node.platform.os == linux]
portainer:
image: portainer/portainer-ce:alpine
command: -H tcp://portainer_agent:9001 --tlsskipverify
ports:
- "9443:9443"
- "9000:9000"
- "8000:8000"
volumes:
- /mnt/docker/portainer/data:/data
networks:
- agent_network
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
networks:
agent_network:
driver: overlay
attachable: true
Jalankan perintah berikut untuk mulai deploy portainer :
$ sudo docker stack deploy -c portainer-agent-stack.yml portainer
Melihat container yang baru dibuat :
$ sudo docker stack ps portainer
Melihat log proses deploy
$ sudo docker service logs portainer_portainer
$ sudo docker service logs portainer_agent
Kalau dibandingkan dengan membangun clustering menggunakan kubernetes, docker swarm jauh lebih sederhana dan hemat resource.
Official Dokumentasi :
Docker Swarm : https://docs.docker.com/engine/swarm/
GlusterFS : https://docs.gluster.org/en/latest/
Keepalived : https://www.keepalived.org/manpage.html
Portainer : https://docs.portainer.io/start/install/server/swarm