Perbarui Elastic Stack secara Otomatis dengan Playbook yang Mungkin

Diterbitkan: 2022-03-11

Analisis log untuk jaringan yang terdiri dari ribuan perangkat dulunya merupakan tugas yang rumit, memakan waktu, dan membosankan sebelum saya memutuskan untuk menggunakan Elastic Stack sebagai solusi logging terpusat. Itu terbukti menjadi keputusan yang sangat bijaksana. Saya tidak hanya memiliki satu tempat untuk mencari semua log saya, tetapi saya mendapatkan hasil yang hampir seketika pada pencarian saya, visualisasi kuat yang sangat membantu untuk analisis dan pemecahan masalah, dan dasbor indah yang memberi saya gambaran umum yang berguna tentang jaringan.

Elastic Stack terus-menerus merilis fitur baru dan luar biasa, menjaga kecepatan pengembangan yang sangat aktif, sering kali memberikan dua rilis baru setiap bulan. Saya ingin selalu memperbarui lingkungan saya untuk memastikan saya dapat memanfaatkan fitur dan peningkatan baru. Juga untuk menjaganya tetap bebas dari bug dan masalah keamanan. Tetapi ini mengharuskan saya untuk terus memperbarui lingkungan.

Meskipun situs web Elastic memelihara dokumentasi yang jelas dan terperinci, termasuk pada proses pemutakhiran produk mereka, pemutakhiran secara manual adalah tugas yang rumit, terutama klaster Elasticsearch. Ada banyak langkah yang terlibat, dan urutan yang sangat spesifik harus diikuti. Itulah mengapa saya memutuskan untuk mengotomatiskan seluruh proses, sejak lama, menggunakan Ansible Playbooks.

Dalam tutorial Ansible ini, saya akan memandu kita melalui serangkaian Playbook Ansible yang dikembangkan untuk meningkatkan otomatis instalasi Elastic Stack saya.

Apa itu Tumpukan Elastis?

Elastic Stack, sebelumnya dikenal sebagai ELK stack, terdiri dari Elasticsearch, Logstash, dan Kibana, dari perusahaan open-source Elastic, yang bersama-sama menyediakan platform yang kuat untuk mengindeks, mencari, dan menganalisis data Anda. Hal ini dapat digunakan untuk berbagai aplikasi. Dari logging dan analisis keamanan hingga manajemen kinerja aplikasi dan pencarian situs.

  • Elasticsearch adalah inti dari tumpukan. Ini adalah mesin pencari dan analitik terdistribusi yang mampu memberikan hasil pencarian hampir real-time bahkan terhadap sejumlah besar data yang disimpan.

  • Logstash adalah pipa pemrosesan yang mendapatkan atau menerima data dari berbagai sumber (50 plugin input resmi saat saya menulis), menguraikannya, memfilter, dan mentransformasikannya dan mengirimkannya ke satu atau lebih kemungkinan keluaran. Dalam kasus kami, kami tertarik dengan plugin keluaran Elasticsearch.

  • Kibana adalah antarmuka pengguna dan operasi Anda. Ini memungkinkan Anda memvisualisasikan, mencari, menavigasi data Anda, dan membuat dasbor yang memberi Anda wawasan luar biasa tentangnya.

Apa itu Ansible?

Ansible adalah platform otomatisasi TI yang dapat digunakan untuk mengonfigurasi sistem, menyebarkan atau meningkatkan perangkat lunak, dan mengatur tugas-tugas TI yang kompleks. Tujuan utamanya adalah kesederhanaan dan kemudahan penggunaan. Fitur favorit saya dari Ansible adalah tanpa agen, artinya saya tidak perlu menginstal dan mengelola perangkat lunak tambahan apa pun pada host dan perangkat yang ingin saya kelola. Kami akan menggunakan kekuatan otomatisasi Ansible untuk mengupgrade Elastic Stack kami secara otomatis.

Penafian dan Peringatan

Playbook yang akan saya bagikan di sini didasarkan pada langkah-langkah yang dijelaskan dalam dokumentasi produk resmi. Ini dimaksudkan untuk digunakan hanya untuk peningkatan versi utama yang sama. Misalnya: 5.x5.y atau 6.x6.y di mana x > y . Peningkatan antara versi utama sering kali memerlukan langkah ekstra dan buku pedoman tersebut tidak akan berfungsi untuk kasus tersebut.

Terlepas dari itu, selalu baca catatan rilis, terutama bagian perubahan yang melanggar sebelum menggunakan buku pedoman untuk meningkatkan. Pastikan Anda memahami tugas yang dijalankan di buku pedoman dan selalu periksa instruksi peningkatan untuk memastikan tidak ada perubahan penting.

Karena itu, saya telah menggunakan buku pedoman itu (atau versi sebelumnya) sejak versi 2.2 dari Elasticsearch tanpa masalah. Pada saat itu saya memiliki buku pedoman yang benar-benar terpisah untuk setiap produk, karena mereka tidak berbagi nomor versi yang sama seperti yang mereka ketahui.

Karena itu, saya tidak bertanggung jawab dengan cara apa pun atas penggunaan informasi yang terkandung dalam artikel ini oleh Anda.

Lingkungan Fiktif Kami

Lingkungan tempat buku pedoman kami akan dijalankan akan terdiri dari 6 server CentOS 7:

  • 1 x Server Logstash
  • 1 x Server Kibana
  • 4 x simpul pencarian elastis

Tidak masalah jika lingkungan Anda memiliki jumlah server yang berbeda. Anda cukup mencerminkannya sesuai dengan file inventaris dan buku pedoman akan berjalan tanpa masalah. Namun, jika Anda tidak menggunakan distribusi berbasis RHEL, saya akan membiarkannya sebagai latihan bagi Anda untuk mengubah beberapa tugas yang spesifik distribusi (terutama hal-hal manajer paket)

Contoh Elastic Stack yang akan diterapkan oleh Playbook Ansible kami

Inventaris

Ansible membutuhkan inventaris untuk mengetahui host mana yang harus menjalankan buku pedoman. Empat skenario imajiner kami, kami akan menggunakan file inventaris berikut:

 [logstash] server01 ansible_host=10.0.0.1 [kibana] server02 ansible_host=10.0.0.2 [elasticsearch] server03 ansible_host=10.0.0.3 server04 ansible_host=10.0.0.4 server05 ansible_host=10.0.0.5 server06 ansible_host=10.0.0.6

Dalam file inventaris Ansible, [section] mana pun mewakili sekelompok host. Inventaris kami memiliki 3 grup host: logstash , kibana , dan elasticsearch . Anda akan melihat bahwa saya hanya menggunakan nama grup di buku pedoman. Itu berarti tidak masalah jumlah host dalam inventaris, selama grupnya benar, playbook akan berjalan.

Proses Peningkatan

Proses upgrade akan terdiri dari langkah-langkah berikut:

1) Pra-unduh paket

2) Peningkatan Logstash

3) Peningkatan Bergulir dari cluster Elasticsearch

4) Peningkatan Kibana

Tujuan utamanya adalah untuk meminimalkan downtime. Sebagian besar waktu pengguna bahkan tidak akan menyadarinya. Terkadang Kibana mungkin tidak tersedia selama beberapa detik. Itu bisa diterima oleh saya.

Playbook Ansible Utama

Proses peningkatan terdiri dari serangkaian buku pedoman yang berbeda. Saya akan menggunakan fitur import_playbook dari Ansible untuk mengatur semua playbook dalam satu file playbook utama yang dapat dipanggil untuk menangani seluruh proses.

 - name: pre-download import_playbook: pre-download.yml - name: logstash-upgrade import_playbook: logstash-upgrade.yml - name: elasticsearch-rolling-upgrade import_playbook: elasticsearch-rolling-upgrade.yml - name: kibana-upgrade import_playbook: kibana-upgrade.yml

Cukup sederhana. Ini hanyalah cara untuk mengatur pelaksanaan buku pedoman dalam satu urutan tertentu.

Sekarang, mari kita pertimbangkan bagaimana kita akan menggunakan contoh buku pedoman Ansible di atas. Saya akan menjelaskan bagaimana kita mengimplementasikannya nanti, tetapi ini adalah perintah yang akan saya jalankan untuk meningkatkan ke versi 6.5.4:

 $ ansible-playbook -i inventory -e elk_version=6.5.4 main.yml

Pra-unduh Paket

Langkah pertama itu sebenarnya opsional. Alasan saya menggunakan ini adalah karena saya menganggap praktik yang baik secara umum untuk menghentikan layanan yang berjalan sebelum memutakhirkannya. Sekarang, jika Anda memiliki koneksi Internet yang cepat, waktu bagi manajer paket Anda untuk mengunduh paket mungkin dapat diabaikan. Tapi itu tidak selalu terjadi dan saya ingin meminimalkan jumlah waktu ketika layanan apa pun tidak aktif. Itulah cara buku pedoman pertama saya akan menggunakan yum untuk mengunduh semua paket sebelumnya. Dengan begitu ketika waktu upgrade tiba, langkah download sudah diurus.

 - hosts: logstash gather_facts: no tasks: - name: Validate logstash Version fail: msg="Invalid ELK Version" when: elk_version is undefined or not elk_version is match("\d+\.\d+\.\d+") - name: Get logstash current version command: rpm -q logstash --qf %{VERSION} args: warn: no changed_when: False register: version_found - name: Pre-download logstash install package yum: name: logstash-{{ elk_version }} download_only: yes when: version_found.stdout is version_compare(elk_version, '<')

Baris pertama menunjukkan bahwa permainan ini hanya akan berlaku untuk grup logstash . Baris kedua memberitahu Ansible untuk tidak repot mengumpulkan fakta tentang tuan rumah. Ini akan mempercepat permainan, tetapi pastikan tidak ada tugas dalam permainan yang membutuhkan fakta tentang tuan rumah.

Tugas pertama dalam permainan akan memvalidasi variabel elk_version . Variabel ini mewakili versi Elastic Stack yang kami tingkatkan. Itu diteruskan saat Anda menjalankan perintah ansible-playbook. Jika variabel tidak lolos atau formatnya tidak valid, permainan akan segera di-bail out. Tugas itu sebenarnya akan menjadi tugas pertama di semua drama. Alasan untuk itu adalah untuk memungkinkan drama dieksekusi secara terpisah jika diinginkan atau perlu.

Tugas kedua akan menggunakan perintah rpm untuk mendapatkan versi Logstash saat ini dan mendaftar di variabel version_found . Informasi itu akan digunakan dalam tugas berikutnya. Baris args: , warn: no dan changed_when: False ada untuk membuat ansible-lint bahagia, tetapi tidak sepenuhnya diperlukan.

Tugas terakhir akan menjalankan perintah yang sebenarnya melakukan pra-unduh paket. Tetapi hanya jika versi Logstash yang diinstal lebih lama dari versi target. Bukan titik unduh dan versi yang lebih lama atau sama jika tidak akan digunakan.

Dua permainan lainnya pada dasarnya sama, kecuali bahwa alih-alih Logstash, mereka akan mengunduh Elasticsearch dan Kibana terlebih dahulu:

 - hosts: elasticsearch gather_facts: no tasks: - name: Validate elasticsearch Version fail: msg="Invalid ELK Version" when: elk_version is undefined or not elk_version is match("\d+\.\d+\.\d+") - name: Get elasticsearch current version command: rpm -q elasticsearch --qf %{VERSION} args: warn: no changed_when: False register: version_found - name: Pre-download elasticsearch install package yum: name: elasticsearch-{{ elk_version }} download_only: yes when: version_found.stdout is version_compare(elk_version, '<') - hosts: kibana gather_facts: no tasks: - name: Validate kibana Version fail: msg="Invalid ELK Version" when: elk_version is undefined or not elk_version is match("\d+\.\d+\.\d+") - name: Get kibana current version command: rpm -q kibana --qf %{VERSION} args: warn: no changed_when: False register: version_found - name: Pre-download kibana install package yum: name: kibana-{{ elk_version }} download_only: yes when: version_found.stdout is version_compare(elk_version, '<')

Peningkatan Logstash

Logstash harus menjadi komponen pertama yang ditingkatkan. Itu karena Logstash dijamin bekerja dengan versi Elasticsearch yang lebih lama.

Tugas pertama permainan identik dengan mitra pra-unduh:

 - name: Upgrade logstash hosts: logstash gather_facts: no tasks: - name: Validate ELK Version fail: msg="Invalid ELK Version" when: elk_version is undefined or not elk_version is match("\d+\.\d+\.\d+") - name: Get logstash current version command: rpm -q logstash --qf %{VERSION} changed_when: False register: version_found

Dua tugas terakhir terkandung dalam satu blok:

 - block: - name: Update logstash yum: name: logstash-{{ elk_version }} state: present - name: Restart logstash systemd: name: logstash state: restarted enabled: yes daemon_reload: yes when: version_found.stdout is version_compare(elk_version, '<')

Conditional when menjamin bahwa tugas di blok hanya akan dijalankan jika versi target lebih baru dari versi saat ini. Tugas pertama di dalam blok melakukan pemutakhiran Logstash dan tugas kedua memulai ulang layanan.

Peningkatan Bergulir Klaster Elasticsearch

Untuk memastikan tidak ada downtime pada cluster Elasticsearch, kita harus melakukan rolling upgrade. Ini berarti bahwa kita akan mengupgrade satu node pada satu waktu, hanya memulai upgrade dari node mana pun setelah kita memastikan bahwa cluster dalam keadaan hijau (sepenuhnya sehat).

Dari awal permainan, Anda akan melihat sesuatu yang berbeda:

 - name: Elasticsearch rolling upgrade hosts: elasticsearch gather_facts: no serial: 1

Di sini kita memiliki serial: 1 . Perilaku default Ansible adalah menjalankan permainan melawan beberapa host secara paralel, jumlah host simultan yang ditentukan dalam konfigurasi. Baris ini memastikan bahwa permainan akan dijalankan hanya terhadap satu host pada satu waktu.

Selanjutnya, kami mendefinisikan beberapa variabel yang akan digunakan di sepanjang permainan:

 vars: es_disable_allocation: '{"transient":{"cluster.routing.allocation.enable":"none"}}' es_enable_allocation: '{"transient":{"cluster.routing.allocation.enable": "all","cluster.routing.allocation.node_concurrent_recoveries": 5,"indices.recovery.max_bytes_per_sec": "500mb"}}' es_http_port: 9200 es_transport_port: 9300

Arti dari setiap variabel akan menjadi jelas ketika mereka muncul dalam permainan.

Seperti biasa, tugas pertama adalah memvalidasi versi target:

 tasks: - name: Validate ELK Version fail: msg="Invalid ELK Version" when: elk_version is undefined or not elk_version is match("\d+\.\d+\.\d+")

Banyak dari tugas berikut akan terdiri dari menjalankan panggilan REST terhadap cluster Elasticsearch. Panggilan dapat dieksekusi terhadap salah satu node. Anda cukup menjalankannya terhadap host saat ini dalam permainan, tetapi beberapa perintah akan dieksekusi saat layanan Elasticsearch tidak aktif untuk host saat ini. Jadi, dalam tugas berikutnya, kami memastikan untuk memilih host yang berbeda untuk menjalankan panggilan REST. Untuk ini, kita akan menggunakan modul set_fact dan variabel groups dari Ansible inventory.

 - name: Set the es_host for the first host set_fact: es_host: "{{ groups.elasticsearch[1] }}" when: "inventory_hostname == groups.elasticsearch[0]" - name: Set the es_host for the remaining hosts set_fact: es_host: "{{ groups.elasticsearch[0] }}" when: "inventory_hostname != groups.elasticsearch[0]"

Selanjutnya, kami memastikan bahwa layanan sudah aktif di node saat ini sebelum melanjutkan:

 - name: Ensure elasticsearch service is running systemd: name: elasticsearch enabled: yes state: started register: response - name: Wait for elasticsearch node to come back up if it was stopped wait_for: port: "{{ es_transport_port }}" delay: 45 when: response.changed == true

Seperti di drama sebelumnya, kami akan memeriksa versi saat ini. Kecuali untuk kali ini, kita akan menggunakan Elasticsearch REST API daripada menjalankan rpm. Kita juga bisa menggunakan perintah rpm, tapi saya ingin menunjukkan alternatif ini.

 - name: Check current version uri: url: http://localhost:{{ es_http_port }} method: GET register: version_found retries: 10 delay: 10

Tugas yang tersisa berada di dalam blok yang hanya akan dieksekusi jika versi saat ini lebih lama dari versi target:

 - block: - name: Enable shard allocation for the cluster uri: url: http://localhost:{{ es_http_port }}/_cluster/settings method: PUT body_format: json body: "{{ es_enable_allocation }}"

Sekarang, jika Anda mengikuti saran saya dan membaca dokumentasi, Anda akan menyadari bahwa langkah ini harus berlawanan: untuk menonaktifkan alokasi shard. Saya suka meletakkan tugas ini di sini terlebih dahulu jika pecahan dinonaktifkan sebelumnya karena alasan tertentu. Ini penting karena tugas selanjutnya akan menunggu cluster menjadi hijau. Jika alokasi shard dinonaktifkan, cluster akan tetap berwarna kuning dan tugas akan hang hingga waktu habis.

Jadi, setelah memastikan bahwa alokasi shard diaktifkan, kami memastikan bahwa cluster dalam status hijau:

 - name: Wait for cluster health to return to green uri: url: http://localhost:{{ es_http_port }}/_cluster/health method: GET register: response until: "response.json.status == 'green'" retries: 500 delay: 15

Setelah layanan node dimulai ulang, kluster membutuhkan waktu lama untuk kembali ke hijau. Itulah alasan mengapa garis retries: 500 dan delay: 15 . Artinya kita akan menunggu 125 menit (500 x 15 detik) agar cluster kembali hijau. Anda mungkin perlu menyesuaikannya jika node Anda menyimpan sejumlah besar data. Untuk sebagian besar kasus, itu jauh lebih dari cukup.

Sekarang kita dapat menonaktifkan alokasi shard:

 - name: Disable shard allocation for the cluster uri: url: http://localhost:{{ es_http_port }}/_cluster/settings method: PUT body_format: json body: {{ es_disable_allocation }}

Dan sebelum mematikan layanan, kami menjalankan opsional, namun disarankan, sinkronisasi flush. Tidak jarang kita mendapatkan error 409 untuk beberapa indeks saat kita melakukan sync flush. Karena ini aman untuk diabaikan, saya menambahkan 409 ke daftar kode status sukses.

 - name: Perform a synced flush uri: url: http://localhost:{{ es_http_port }}/_flush/synced method: POST status_code: "200, 409"

Sekarang, simpul ini siap untuk ditingkatkan:

 - name: Shutdown elasticsearch node systemd: name: elasticsearch state: stopped - name: Update elasticsearch yum: name: elasticsearch-{{ elk_version }} state: present

Dengan layanan dihentikan, kami menunggu semua pecahan dialokasikan sebelum memulai simpul lagi:

 - name: Wait for all shards to be reallocated uri: url=http://{{ es_host }}:{{ es_http_port }}/_cluster/health method=GET register: response until: "response.json.relocating_shards == 0" retries: 20 delay: 15

Setelah pecahan dialokasikan kembali, kami memulai kembali layanan Elasticsearch dan menunggu sampai benar-benar siap:

 - name: Start elasticsearch systemd: name: elasticsearch state: restarted enabled: yes daemon_reload: yes - name: Wait for elasticsearch node to come back up wait_for: port: "{{ es_transport_port }}" delay: 35 - name: Wait for elasticsearch http to come back up wait_for: port: "{{ es_http_port }}" delay: 5

Sekarang kami memastikan bahwa cluster berwarna kuning atau hijau sebelum mengaktifkan kembali alokasi shard:

 - name: Wait for cluster health to return to yellow or green uri: url: http://localhost:{{ es_http_port }}/_cluster/health method: GET register: response until: "response.json.status == 'yellow' or response.json.status == 'green'" retries: 500 delay: 15 - name: Enable shard allocation for the cluster uri: url: http://localhost:{{ es_http_port }}/_cluster/settings method: PUT body_format: json body: "{{ es_enable_allocation }}" register: response until: "response.json.acknowledged == true" retries: 10 delay: 15

Dan kami menunggu node pulih sepenuhnya sebelum memproses yang berikutnya:

 - name: Wait for the node to recover uri: url: http://localhost:{{ es_http_port }}/_cat/health method: GET return_content: yes register: response until: "'green' in response.content" retries: 500 delay: 15

Tentu saja, seperti yang saya katakan sebelumnya, blok ini hanya boleh dijalankan jika kita benar-benar memutakhirkan versi:

 when: version_found.json.version.number is version_compare(elk_version, '<')

Peningkatan Kibana

Komponen terakhir yang diupgrade adalah Kibana.

Seperti yang Anda duga, tugas pertama tidak berbeda dari pemutakhiran Logstash atau pemutaran pra-unduh. Kecuali untuk definisi satu variabel:

 - name: Upgrade kibana hosts: kibana gather_facts: no vars: set_default_index: '{"changes":{"defaultIndex":"syslog"}}' tasks: - name: Validate ELK Version fail: msg="Invalid ELK Version" when: elk_version is undefined or not elk_version is match("\d+\.\d+\.\d+") - name: Get kibana current version command: rpm -q kibana --qf %{VERSION} args: warn: no changed_when: False register: version_found

Saya akan menjelaskan variabel set_default_index ketika kita sampai pada tugas yang menggunakannya.

Sisa tugas akan berada di dalam blok yang hanya akan dijalankan jika versi Kibana yang diinstal lebih lama dari versi target. Dua tugas pertama akan memperbarui dan memulai ulang Kibana:

 - name: Update kibana yum: name: kibana-{{ elk_version }} state: present - name: Restart kibana systemd: name: kibana state: restarted enabled: yes daemon_reload: yes

Dan untuk Kibana itu sudah cukup. Sayangnya, untuk beberapa alasan, setelah upgrade, Kibana kehilangan referensi ke pola indeks defaultnya. Ini menyebabkannya meminta pengguna pertama yang mengakses setelah pemutakhiran untuk menentukan pola indeks default, yang dapat menyebabkan kebingungan. Untuk menghindarinya pastikan untuk menyertakan tugas untuk mengatur ulang pola indeks default. Pada contoh di bawah ini, ini adalah syslog , tetapi Anda harus mengubahnya menjadi apa pun yang Anda gunakan. Namun, sebelum mengatur indeks, kita harus memastikan bahwa Kibana sudah aktif dan siap melayani permintaan:

 - name: Wait for kibana to start listening wait_for: port: 5601 delay: 5 - name: Wait for kibana to be ready uri: url: http://localhost:5601/api/kibana/settings method: GET register: response until: "'kbn_name' in response and response.status == 200" retries: 30 delay: 5 - name: Set Default Index uri: url: http://localhost:5601/api/kibana/settings method: POST body_format: json body: "{{ set_default_index }}" headers: "kbn-version": "{{ elk_version }}"

Kesimpulan

Elastic Stack adalah alat yang berharga dan saya merekomendasikan Anda untuk melihatnya jika Anda belum menggunakannya. Ini sangat bagus dan terus meningkat, sedemikian rupa sehingga mungkin sulit untuk mengikuti peningkatan yang konstan. Saya berharap Ansible Playbooks itu mungkin berguna bagi Anda seperti halnya bagi saya.

Saya membuatnya tersedia di GitHub di https://github.com/orgito/elk-upgrade. Saya sarankan Anda mengujinya di lingkungan non-produksi.

Jika Anda seorang pengembang Ruby on Rails yang ingin memasukkan Elasticsearch dalam aplikasi Anda, lihat Elasticsearch untuk Ruby on Rails: A Tutorial to the Chewy Gem oleh Core Toptal Software Engineer Arkadiy Zabazhanov.