Provision Cluster

Provision Cluster #

Membangun cluster Kubernetes dari awal adalah proses yang melibatkan banyak langkah berurutan: setup OS yang konsisten di semua node, instalasi container runtime, instalasi komponen Kubernetes, inisialisasi control plane, dan join worker nodes. Melakukan ini secara manual di 10+ server adalah pekerjaan yang melelahkan dan rawan kesalahan. Ansible mengotomasi seluruh proses ini menjadi satu perintah yang bisa diulang dan menghasilkan cluster yang identik setiap kali.

Struktur Inventory untuk Kubernetes #

# inventory/k8s-cluster/hosts.ini
[control_plane]
k8s-master-01 ansible_host=10.0.1.10
k8s-master-02 ansible_host=10.0.1.11   # Untuk HA control plane
k8s-master-03 ansible_host=10.0.1.12

[worker_nodes]
k8s-worker-01 ansible_host=10.0.2.10
k8s-worker-02 ansible_host=10.0.2.11
k8s-worker-03 ansible_host=10.0.2.12

[k8s_cluster:children]
control_plane
worker_nodes

Persiapan OS di Semua Node #

Sebelum menginstal Kubernetes, semua node harus dikonfigurasi dengan cara yang sama:

# roles/k8s-common/tasks/main.yml
---
- name: Nonaktifkan swap (Kubernetes tidak support swap)
  command: swapoff -a
  changed_when: false

- name: Pastikan swap dinonaktifkan permanen
  replace:
    path: /etc/fstab
    regexp: '^([^#].*?\sswap\s+sw\s+.*)$'
    replace: '# \1'

- name: Load kernel module yang diperlukan
  modprobe:
    name: "{{ item }}"
    state: present
  loop:
    - overlay
    - br_netfilter

- name: Pastikan module dimuat saat boot
  template:
    src: k8s-modules.conf.j2
    dest: /etc/modules-load.d/k8s.conf

- name: Konfigurasi sysctl untuk Kubernetes networking
  sysctl:
    name: "{{ item.key }}"
    value: "{{ item.value }}"
    state: present
    reload: true
  loop:
    - { key: "net.bridge.bridge-nf-call-iptables",  value: "1" }
    - { key: "net.bridge.bridge-nf-call-ip6tables", value: "1" }
    - { key: "net.ipv4.ip_forward",                 value: "1" }

Instalasi Container Runtime (containerd) #

Kubernetes modern menggunakan containerd sebagai container runtime:

# roles/containerd/tasks/main.yml
---
- name: Install containerd
  apt:
    name: containerd.io
    state: present

- name: Buat direktori konfigurasi containerd
  file:
    path: /etc/containerd
    state: directory

- name: Generate konfigurasi default containerd
  command: containerd config default
  register: containerd_default_config
  changed_when: false

- name: Simpan konfigurasi containerd
  copy:
    content: "{{ containerd_default_config.stdout }}"
    dest: /etc/containerd/config.toml

- name: Aktifkan SystemdCgroup di containerd
  replace:
    path: /etc/containerd/config.toml
    regexp: 'SystemdCgroup = false'
    replace: 'SystemdCgroup = true'
  notify: Restart containerd

- name: Pastikan containerd berjalan
  systemd:
    name: containerd
    state: started
    enabled: true

Instalasi Komponen Kubernetes #

# roles/k8s-packages/tasks/main.yml
---
- name: Tambahkan GPG key Kubernetes
  apt_key:
    url: https://pkgs.k8s.io/core:/stable:/v{{ k8s_minor_version }}/deb/Release.key
    state: present

- name: Tambahkan repository Kubernetes
  apt_repository:
    repo: "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v{{ k8s_minor_version }}/deb/ /"
    state: present

- name: Install kubeadm, kubelet, kubectl
  apt:
    name:
      - "kubelet={{ k8s_version }}-*"
      - "kubeadm={{ k8s_version }}-*"
      - "kubectl={{ k8s_version }}-*"
    state: present
    update_cache: true

- name: Pin versi Kubernetes agar tidak terupdate otomatis
  dpkg_selections:
    name: "{{ item }}"
    selection: hold
  loop:
    - kubelet
    - kubeadm
    - kubectl

Inisialisasi Control Plane #

# playbooks/init-control-plane.yml
---
- name: Inisialisasi Kubernetes control plane
  hosts: control_plane[0]    # Hanya di control plane pertama
  become: true
  tasks:
    - name: Cek apakah cluster sudah diinisialisasi
      stat:
        path: /etc/kubernetes/admin.conf
      register: k8s_init_check

    - name: Inisialisasi cluster dengan kubeadm
      command: >
        kubeadm init
        --pod-network-cidr={{ pod_network_cidr }}
        --control-plane-endpoint={{ control_plane_endpoint }}
        --kubernetes-version={{ k8s_version }}        
      register: kubeadm_init
      when: not k8s_init_check.stat.exists

    - name: Buat direktori .kube untuk user current
      file:
        path: "{{ ansible_env.HOME }}/.kube"
        state: directory

    - name: Copy kubeconfig ke home directory
      copy:
        src: /etc/kubernetes/admin.conf
        dest: "{{ ansible_env.HOME }}/.kube/config"
        remote_src: true
        owner: "{{ ansible_user }}"

    - name: Ambil join command untuk worker nodes
      command: kubeadm token create --print-join-command
      register: join_command
      changed_when: false

    - name: Simpan join command sebagai fact
      set_fact:
        k8s_join_command: "{{ join_command.stdout }}"
      delegate_to: localhost
      delegate_facts: true

    - name: Install CNI plugin (Calico)
      command: kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
      environment:
        KUBECONFIG: /etc/kubernetes/admin.conf
      when: not k8s_init_check.stat.exists

Join Worker Nodes #

# playbooks/join-workers.yml
---
- name: Join worker nodes ke cluster
  hosts: worker_nodes
  become: true
  tasks:
    - name: Cek apakah node sudah bergabung ke cluster
      stat:
        path: /etc/kubernetes/kubelet.conf
      register: kubelet_conf

    - name: Join node ke cluster
      command: "{{ hostvars['localhost']['k8s_join_command'] }}"
      when: not kubelet_conf.stat.exists

    - name: Tunggu node menjadi Ready
      command: >
        kubectl get node {{ ansible_hostname }}
        --kubeconfig /etc/kubernetes/admin.conf
        -o jsonpath='{.status.conditions[-1].type}'        
      register: node_status
      until: node_status.stdout == "Ready"
      retries: 20
      delay: 15
      delegate_to: "{{ groups['control_plane'][0] }}"
      changed_when: false

Ambil kubeconfig ke Control Node #

- name: Ambil kubeconfig ke control node lokal
  hosts: control_plane[0]
  tasks:
    - name: Fetch kubeconfig
      fetch:
        src: /etc/kubernetes/admin.conf
        dest: "{{ playbook_dir }}/kubeconfig/admin.conf"
        flat: true

Ringkasan #

  • Swap harus dinonaktifkan di semua node sebelum menginstal Kubernetes — Kubernetes tidak mendukung swap.
  • Konfigurasi sysctl (br_netfilter, ip_forward) wajib diaktifkan agar networking Kubernetes berfungsi.
  • Gunakan containerd dengan SystemdCgroup = true sebagai container runtime — ini adalah konfigurasi yang direkomendasikan.
  • Pin versi kubeadm, kubelet, dan kubectl dengan hold — update yang tidak disengaja bisa merusak cluster.
  • Inisialisasi control plane hanya sekali di satu node — gunakan control_plane[0] sebagai target host.
  • Simpan join command dari control plane sebagai fact dan gunakan di playbook join worker — jangan hardcode di inventory.
  • Selalu fetch kubeconfig ke control node setelah cluster siap agar bisa mengelola cluster dari lokal.

← Sebelumnya: Apa itu Kubernetes?   Berikutnya: Deploy Manifest →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact