Menyiapkan server untuk menyebarkan aplikasi Rails menggunakan Ansible

Belum lama ini saya perlu menulis beberapa buku pedoman yang mungkin untuk mempersiapkan server untuk menerapkan aplikasi Rails. Dan yang mengejutkan, saya tidak menemukan panduan langkah demi langkah yang sederhana. Saya tidak ingin menyalin pedoman orang lain tanpa memahami apa yang terjadi, dan pada akhirnya saya harus membaca dokumentasinya, mengumpulkan semuanya sendiri. Mungkin saya bisa membantu seseorang mempercepat proses ini dengan bantuan artikel ini.

Hal pertama yang harus dipahami adalah bahwa ansible memberi Anda antarmuka yang nyaman untuk melakukan daftar tindakan yang telah ditentukan sebelumnya pada server jarak jauh melalui SSH. Tidak ada keajaiban di sini, Anda tidak dapat menginstal plugin dan mendapatkan penerapan zero downtime pada aplikasi Anda dengan buruh pelabuhan, pemantauan, dan fasilitas lainnya. Untuk menulis pedoman, Anda harus mengetahui apa sebenarnya yang ingin Anda lakukan dan bagaimana melakukannya. Itu sebabnya saya tidak puas dengan pedoman siap pakai dari GitHub, atau artikel seperti: β€œSalin dan jalankan, itu akan berhasil.”

Apa yang kita butuhkan?

Seperti yang sudah saya katakan, untuk menulis buku pedoman, Anda perlu mengetahui apa yang ingin Anda lakukan dan bagaimana melakukannya. Mari kita putuskan apa yang kita butuhkan. Untuk aplikasi Rails kita memerlukan beberapa paket sistem: nginx, postgresql (redis, dll). Selain itu, kami memerlukan versi ruby ​​​​yang spesifik. Yang terbaik adalah menginstalnya melalui rbenv (rvm, asdf...). Menjalankan semua ini sebagai pengguna root selalu merupakan ide buruk, jadi Anda perlu membuat pengguna terpisah dan mengonfigurasi haknya. Setelah ini, Anda perlu mengunggah kode kami ke server, menyalin konfigurasi untuk nginx, postgres, dll dan memulai semua layanan ini.

Hasilnya, urutan tindakannya adalah sebagai berikut:

  1. Masuk sebagai root
  2. menginstal paket sistem
  3. buat pengguna baru, konfigurasikan hak, kunci ssh
  4. konfigurasikan paket sistem (nginx dll) dan jalankan
  5. Kami membuat pengguna di database (Anda dapat langsung membuat database)
  6. Masuk sebagai pengguna baru
  7. Instal rbenv dan Ruby
  8. Memasang bundler
  9. Mengunggah kode aplikasi
  10. Meluncurkan server Puma

Selain itu, tahapan terakhir dapat dilakukan dengan menggunakan capistrano, setidaknya ia dapat menyalin kode ke direktori rilis, mengganti rilis dengan symlink setelah penerapan berhasil, menyalin konfigurasi dari direktori bersama, memulai ulang puma, dll. Semua ini bisa dilakukan dengan menggunakan Ansible, tapi mengapa?

Struktur file

Ansible memiliki ketat struktur file untuk semua file Anda, jadi sebaiknya simpan semuanya di direktori terpisah. Selain itu, tidak begitu penting apakah itu akan berada dalam aplikasi rel itu sendiri, atau secara terpisah. Anda dapat menyimpan file di repositori git terpisah. Secara pribadi, menurut saya paling mudah untuk membuat direktori yang memungkinkan di direktori /config aplikasi Rails dan menyimpan semuanya dalam satu repositori.

Buku Pedoman Sederhana

Playbook adalah file yml yang, menggunakan sintaks khusus, menjelaskan apa yang harus dilakukan Ansible dan bagaimana caranya. Mari kita buat pedoman pertama yang tidak melakukan apa pun:

---
- name: Simple playbook
  hosts: all

Di sini kami hanya mengatakan bahwa buku pedoman kami disebut Simple Playbook dan isinya harus dijalankan untuk semua host. Kita dapat menyimpannya di direktori /ansible dengan nama playbook.yml dan coba jalankan:

ansible-playbook ./playbook.yml

PLAY [Simple Playbook] ************************************************************************************************************************************
skipping: no hosts matched

Ansible mengatakan tidak mengetahui host mana pun yang cocok dengan semua daftar. Mereka harus dicantumkan secara khusus berkas inventaris.

Mari kita buat di direktori yang sama:

123.123.123.123

Beginilah cara kami menentukan host (idealnya host VPS kami untuk pengujian, atau Anda dapat mendaftarkan localhost) dan menyimpannya dengan nama inventory.
Anda dapat mencoba menjalankan kemungkinan dengan file inventaris:

ansible-playbook ./playbook.yml -i inventory
PLAY [Simple Playbook] ************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************

PLAY RECAP ************************************************************************************************************************************

Jika Anda memiliki akses ssh ke host yang ditentukan, maka kemungkinan akan terhubung dan mengumpulkan informasi tentang sistem jarak jauh. (TUGAS default [Mengumpulkan Fakta]) setelah itu akan memberikan laporan singkat tentang pelaksanaannya (PLAY RECAP).

Secara default, koneksi menggunakan nama pengguna yang Anda gunakan untuk masuk ke sistem. Kemungkinan besar tidak akan ada pada tuan rumah. Dalam file playbook, Anda dapat menentukan pengguna mana yang akan digunakan untuk terhubung menggunakan direktif remote_user. Selain itu, informasi tentang sistem jarak jauh mungkin sering kali tidak Anda perlukan dan Anda tidak perlu membuang waktu untuk mengumpulkannya. Tugas ini juga dapat dinonaktifkan:

---
- name: Simple playbook
  hosts: all
  remote_user: root
  become: true
  gather_facts: no

Coba jalankan playbook lagi dan pastikan koneksi berfungsi. (Jika Anda menentukan pengguna root, maka Anda juga perlu menentukan arahan menjadi: true untuk mendapatkan hak yang lebih tinggi. Seperti yang tertulis dalam dokumentasi: become set to β€˜true’/’yes’ to activate privilege escalation. meskipun tidak sepenuhnya jelas alasannya).

Mungkin Anda akan menerima kesalahan yang disebabkan oleh fakta bahwa ansible tidak dapat menentukan juru bahasa Python, maka Anda dapat menentukannya secara manual:

ansible_python_interpreter: /usr/bin/python3 

Anda dapat mengetahui di mana Anda memiliki python dengan perintah whereis python.

Menginstal paket sistem

Distribusi standar Ansible mencakup banyak modul untuk bekerja dengan berbagai paket sistem, jadi kita tidak perlu menulis skrip bash untuk alasan apa pun. Sekarang kita memerlukan salah satu modul ini untuk memperbarui sistem dan menginstal paket sistem. Saya memiliki Ubuntu Linux di VPS saya, jadi untuk menginstal paket saya menggunakan apt-get ΠΈ modul untuk itu. Jika Anda menggunakan sistem operasi yang berbeda, maka Anda mungkin memerlukan modul yang berbeda (ingat, saya katakan di awal bahwa kita perlu mengetahui terlebih dahulu apa dan bagaimana yang akan kita lakukan). Namun, sintaksisnya kemungkinan besar akan serupa.

Mari lengkapi buku pedoman kita dengan tugas pertama:

---
- name: Simple playbook
  hosts: all
  remote_user: root
  become: true
  gather_facts: no

  tasks:
    - name: Update system
      apt: update_cache=yes
    - name: Install system dependencies
      apt:
        name: git,nginx,redis,postgresql,postgresql-contrib
        state: present

Tugas adalah tugas persis yang akan dilakukan Ansible di server jarak jauh. Kami memberi nama tugas tersebut sehingga kami dapat melacak pelaksanaannya di log. Dan kami menjelaskan, menggunakan sintaks modul tertentu, apa yang perlu dilakukannya. Pada kasus ini apt: update_cache=yes - mengatakan untuk memperbarui paket sistem menggunakan modul apt. Perintah kedua sedikit lebih rumit. Kami meneruskan daftar paket ke modul apt dan mengatakan bahwa itu memang benar state harus menjadi present, artinya, kami katakan instal paket-paket ini. Dengan cara serupa, kita dapat meminta mereka untuk menghapusnya, atau memperbaruinya hanya dengan mengubahnya state. Harap dicatat bahwa agar Rails dapat bekerja dengan postgresql kita memerlukan paket postgresql-contrib, yang sedang kita instal sekarang. Sekali lagi, Anda perlu mengetahui dan melakukan ini; ansible sendiri tidak akan melakukan ini.

Coba jalankan playbook lagi dan periksa apakah paket sudah diinstal.

Membuat pengguna baru.

Untuk bekerja dengan pengguna, Ansible juga memiliki modul - pengguna. Mari tambahkan satu tugas lagi (saya menyembunyikan bagian pedoman yang sudah diketahui di balik komentar agar tidak menyalin seluruhnya setiap saat):

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Add a new user
      user:
        name: my_user
        shell: /bin/bash
        password: "{{ 123qweasd | password_hash('sha512') }}"

Kami membuat pengguna baru, menetapkan skema dan kata sandi untuk itu. Dan kemudian kita mengalami beberapa masalah. Bagaimana jika nama pengguna harus berbeda untuk host yang berbeda? Dan menyimpan kata sandi dalam teks yang jelas di buku pedoman adalah ide yang sangat buruk. Untuk memulainya, mari kita masukkan nama pengguna dan kata sandi ke dalam variabel, dan di akhir artikel saya akan menunjukkan cara mengenkripsi kata sandi.

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Add a new user
      user:
        name: "{{ user }}"
        shell: /bin/bash
        password: "{{ user_password | password_hash('sha512') }}"

Variabel diatur dalam buku pedoman menggunakan kurung kurawal ganda.

Kami akan menunjukkan nilai variabel dalam file inventaris:

123.123.123.123

[all:vars]
user=my_user
user_password=123qweasd

Harap perhatikan arahannya [all:vars] - dikatakan bahwa blok teks berikutnya adalah variabel (vars) dan berlaku untuk semua host (semua).

Desainnya juga menarik "{{ user_password | password_hash('sha512') }}". Masalahnya adalah kemungkinan tidak menginstal pengguna melalui user_add seperti Anda akan melakukannya secara manual. Dan ini menyimpan semua data secara langsung, itulah sebabnya kita juga harus mengubah kata sandi menjadi hash terlebih dahulu, itulah yang dilakukan perintah ini.

Mari tambahkan pengguna kita ke grup sudo. Namun, sebelum ini kita perlu memastikan bahwa grup tersebut ada karena tidak ada yang akan melakukan ini untuk kita:

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Ensure a 'sudo' group
      group:
        name: sudo
        state: present
    - name: Add a new user
      user:
        name: "{{ user }}"
        shell: /bin/bash
        password: "{{ user_password | password_hash('sha512') }}"
        groups: "sudo"

Semuanya cukup sederhana, kami juga memiliki modul grup untuk membuat grup, dengan sintaks yang sangat mirip dengan apt. Maka cukup mendaftarkan grup ini ke pengguna (groups: "sudo").
Hal ini juga berguna untuk menambahkan kunci ssh ke pengguna ini sehingga kita dapat login menggunakannya tanpa kata sandi:

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Ensure a 'sudo' group
      group:
      name: sudo
        state: present
    - name: Add a new user
      user:
        name: "{{ user }}"
        shell: /bin/bash
        password: "{{ user_password | password_hash('sha512') }}"
        groups: "sudo"
    - name: Deploy SSH Key
      authorized_key:
        user: "{{ user }}"
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
        state: present

Dalam hal ini, desainnya menarik "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" β€” menyalin konten file id_rsa.pub (nama Anda mungkin berbeda), yaitu bagian publik dari kunci ssh dan mengunggahnya ke daftar kunci resmi untuk pengguna di server.

Peran

Ketiga tugas untuk menciptakan kegunaan dapat dengan mudah diklasifikasikan ke dalam satu kelompok tugas, dan sebaiknya simpan kelompok ini secara terpisah dari buku pedoman utama agar tidak bertambah terlalu besar. Untuk tujuan ini, Ansible punya ΠΎΠ»ΠΈ.
Menurut struktur file yang ditunjukkan di awal, peran harus ditempatkan di direktori peran terpisah, untuk setiap peran ada direktori terpisah dengan nama yang sama, di dalam direktori tugas, file, templat, dll.
Mari buat struktur file: ./ansible/roles/user/tasks/main.yml (utama adalah file utama yang akan dimuat dan dieksekusi ketika suatu peran terhubung ke buku pedoman; file peran lain dapat dihubungkan ke sana). Sekarang Anda dapat mentransfer semua tugas yang terkait dengan pengguna ke file ini:

# Create user and add him to groups
- name: Ensure a 'sudo' group
  group:
    name: sudo
    state: present

- name: Add a new user
  user:
    name: "{{ user }}"
    shell: /bin/bash
    password: "{{ user_password | password_hash('sha512') }}"
    groups: "sudo"

- name: Deploy SSH Key
  authorized_key:
    user: "{{ user }}"
    key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
    state: present

Di buku pedoman utama, Anda harus menentukan untuk menggunakan peran pengguna:

---
- name: Simple playbook
  hosts: all
  remote_user: root
  gather_facts: no

  tasks:
    - name: Update system
      apt: update_cache=yes
    - name: Install system dependencies
      apt:
        name: git,nginx,redis,postgresql,postgresql-contrib
        state: present

  roles:
    - user

Selain itu, mungkin masuk akal untuk memperbarui sistem sebelum melakukan semua tugas lainnya; untuk melakukan ini, Anda dapat mengganti nama blok tasks di mana mereka didefinisikan pre_tasks.

Menyiapkan nginx

Kita seharusnya sudah menginstal Nginx; kita perlu mengkonfigurasinya dan menjalankannya. Ayo segera lakukan dalam peran tersebut. Mari buat struktur file:

- ansible
  - roles
    - nginx
      - files
      - tasks
        - main.yml
      - templates

Sekarang kita membutuhkan file dan template. Perbedaan di antara keduanya adalah kemungkinan menyalin file secara langsung, apa adanya. Dan template harus memiliki ekstensi j2 dan dapat menggunakan nilai variabel menggunakan kurung kurawal ganda yang sama.

Mari aktifkan nginx main.yml mengajukan. Untuk ini kami memiliki modul systemd:

# Copy nginx configs and start it
- name: enable service nginx and start
  systemd:
    name: nginx
    state: started
    enabled: yes

Di sini kami tidak hanya mengatakan bahwa nginx harus dimulai (yaitu, kami meluncurkannya), tetapi kami langsung mengatakan bahwa itu harus diaktifkan.
Sekarang mari kita salin file konfigurasi:

# Copy nginx configs and start it
- name: enable service nginx and start
  systemd:
    name: nginx
    state: started
    enabled: yes

- name: Copy the nginx.conf
  copy:
    src: nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    backup: yes

- name: Copy template my_app.conf
  template:
    src: my_app_conf.j2
    dest: /etc/nginx/sites-available/my_app.conf
    owner: root
    group: root
    mode: '0644'

Kami membuat file konfigurasi nginx utama (Anda dapat mengambilnya langsung dari server, atau menulisnya sendiri). Dan juga file konfigurasi untuk aplikasi kita di direktori sites_available (ini tidak perlu tetapi berguna). Dalam kasus pertama, kita menggunakan modul copy untuk menyalin file (file harus dalam format /ansible/roles/nginx/files/nginx.conf). Yang kedua, kita menyalin template, menggantikan nilai variabel. Templatnya harus masuk /ansible/roles/nginx/templates/my_app.j2). Dan itu mungkin terlihat seperti ini:

upstream {{ app_name }} {
  server unix:{{ app_path }}/shared/tmp/sockets/puma.sock;
}

server {
  listen 80;
  server_name {{ server_name }} {{ inventory_hostname }};
  root {{ app_path }}/current/public;

  try_files $uri/index.html $uri.html $uri @{{ app_name }};
  ....
}

Perhatikan sisipannya {{ app_name }}, {{ app_path }}, {{ server_name }}, {{ inventory_hostname }} β€” ini semua adalah variabel yang nilainya akan diganti oleh Ansible ke dalam templat sebelum disalin. Ini berguna jika Anda menggunakan pedoman untuk kelompok host yang berbeda. Misalnya, kita dapat menambahkan file inventaris kita:

[production]
123.123.123.123

[staging]
231.231.231.231

[all:vars]
user=my_user
user_password=123qweasd

[production:vars]
server_name=production
app_path=/home/www/my_app
app_name=my_app

[staging:vars]
server_name=staging
app_path=/home/www/my_stage
app_name=my_stage_app

Jika sekarang kami meluncurkan buku pedoman kami, buku pedoman tersebut akan melakukan tugas yang ditentukan untuk kedua host. Namun pada saat yang sama, untuk host pementasan, variabelnya akan berbeda dari variabel produksi, dan tidak hanya dalam peran dan pedoman, tetapi juga dalam konfigurasi nginx. {{ inventory_hostname }} tidak perlu ditentukan dalam file inventaris - ini variabel khusus yang memungkinkan dan host yang sedang menjalankan pedoman tersebut disimpan di sana.
Jika Anda ingin memiliki file inventaris untuk beberapa host, tetapi hanya dijalankan untuk satu grup, hal ini dapat dilakukan dengan perintah berikut:

ansible-playbook -i inventory ./playbook.yml -l "staging"

Pilihan lainnya adalah memiliki file inventaris terpisah untuk grup berbeda. Atau Anda dapat menggabungkan kedua pendekatan tersebut jika Anda memiliki banyak host yang berbeda.

Mari kembali ke pengaturan nginx. Setelah menyalin file konfigurasi, kita perlu membuat symlink di sitest_enabled ke my_app.conf dari sites_available. Dan mulai ulang nginx.

... # old code in mail.yml

- name: Create symlink to sites-enabled
  file:
    src: /etc/nginx/sites-available/my_app.conf
    dest: /etc/nginx/sites-enabled/my_app.conf
    state: link

- name: restart nginx
  service:
    name: nginx
    state: restarted

Semuanya sederhana di sini - sekali lagi modul yang memungkinkan dengan sintaks yang cukup standar. Tapi ada satu hal. Tidak ada gunanya me-restart nginx setiap saat. Pernahkah Anda memperhatikan bahwa kami tidak menulis perintah seperti: "lakukan ini seperti ini", sintaksnya lebih seperti "ini harus memiliki status ini". Dan paling sering inilah cara kerjanya. Jika grup sudah ada, atau paket sistem sudah diinstal, maka kemungkinan akan memeriksanya dan melewati tugas tersebut. Selain itu, file tidak akan disalin jika benar-benar cocok dengan yang sudah ada di server. Kita dapat memanfaatkan ini dan me-restart nginx hanya jika file konfigurasi telah diubah. Ada arahan register untuk ini:

# Copy nginx configs and start it
- name: enable service nginx and start
  systemd:
    name: nginx
    state: started
    enabled: yes

- name: Copy the nginx.conf
  copy:
    src: nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    backup: yes
  register: restart_nginx

- name: Copy template my_app.conf
  template:
    src: my_app_conf.j2
    dest: /etc/nginx/sites-available/my_app.conf
    owner: root
    group: root
    mode: '0644'
  register: restart_nginx

- name: Create symlink to sites-enabled
  file:
    src: /etc/nginx/sites-available/my_app.conf
    dest: /etc/nginx/sites-enabled/my_app.conf
    state: link

- name: restart nginx
  service:
    name: nginx
    state: restarted
  when: restart_nginx.changed

Jika salah satu file konfigurasi berubah, salinan akan dibuat dan variabel akan didaftarkan restart_nginx. Dan hanya jika variabel ini telah didaftarkan, layanan akan dimulai ulang.

Dan, tentu saja, Anda perlu menambahkan peran nginx ke buku pedoman utama.

Menyiapkan postgresql

Kita perlu mengaktifkan postgresql menggunakan systemd dengan cara yang sama seperti yang kita lakukan dengan nginx, dan juga membuat pengguna yang akan kita gunakan untuk mengakses database dan database itu sendiri.
Mari kita buat peran /ansible/roles/postgresql/tasks/main.yml:

# Create user in postgresql
- name: enable postgresql and start
  systemd:
    name: postgresql
    state: started
    enabled: yes

- name: Create database user
  become_user: postgres
  postgresql_user:
    name: "{{ db_user }}"
    password: "{{ db_password }}"
    role_attr_flags: SUPERUSER

- name: Create database
  become_user: postgres
  postgresql_db:
    name: "{{ db_name }}"
    encoding: UTF-8
    owner: "{{ db_user }}"

Saya tidak akan menjelaskan cara menambahkan variabel ke inventaris, ini sudah dilakukan berkali-kali, begitu juga dengan sintaks modul postgresql_db dan postgresql_user. Informasi lebih lanjut dapat ditemukan di dokumentasi. Arahan paling menarik di sini adalah become_user: postgres. Faktanya adalah secara default, hanya pengguna postgres yang memiliki akses ke database postgresql dan hanya secara lokal. Arahan ini memungkinkan kita untuk menjalankan perintah atas nama pengguna ini (tentu saja jika kita memiliki akses).
Selain itu, Anda mungkin harus menambahkan baris ke pg_hba.conf untuk mengizinkan pengguna baru mengakses database. Ini dapat dilakukan dengan cara yang sama seperti kita mengubah konfigurasi nginx.

Dan tentu saja, Anda perlu menambahkan peran postgresql ke buku pedoman utama.

Menginstal Ruby melalui rbenv

Ansible tidak memiliki modul untuk bekerja dengan rbenv, tetapi diinstal dengan mengkloning repositori git. Oleh karena itu, masalah ini menjadi masalah yang paling tidak standar. Mari kita buatkan peran untuknya /ansible/roles/ruby_rbenv/main.yml dan mari kita mulai mengisinya:

# Install rbenv and ruby
- name: Install rbenv
  become_user: "{{ user }}"
  git: repo=https://github.com/rbenv/rbenv.git dest=~/.rbenv

Kami kembali menggunakan arahan menjadi_user untuk bekerja di bawah pengguna yang kami buat untuk tujuan ini. Karena rbenv diinstal di direktori home-nya, dan bukan secara global. Dan kami juga menggunakan modul git untuk mengkloning repositori, menentukan repo dan tujuan.

Selanjutnya, kita perlu mendaftarkan rbenv init di bashrc dan menambahkan rbenv ke PATH di sana. Untuk ini kami memiliki modul lineinfile:

- name: Add rbenv to PATH
  become_user: "{{ user }}"
  lineinfile:
    path: ~/.bashrc
    state: present
    line: 'export PATH="${HOME}/.rbenv/bin:${PATH}"'

- name: Add rbenv init to bashrc
  become_user: "{{ user }}"
  lineinfile:
    path: ~/.bashrc
    state: present
    line: 'eval "$(rbenv init -)"'

Maka Anda perlu menginstal ruby_build:

- name: Install ruby-build
  become_user: "{{ user }}"
  git: repo=https://github.com/rbenv/ruby-build.git dest=~/.rbenv/plugins/ruby-build

Dan terakhir instal ruby. Ini dilakukan melalui rbenv, cukup dengan perintah bash:

- name: Install ruby
  become_user: "{{ user }}"
  shell: |
    export PATH="${HOME}/.rbenv/bin:${PATH}"
    eval "$(rbenv init -)"
    rbenv install {{ ruby_version }}
  args:
    executable: /bin/bash

Kami mengatakan perintah mana yang harus dijalankan dan dengan apa. Namun, di sini kita menemukan fakta bahwa ansible tidak menjalankan kode yang terdapat dalam bashrc sebelum menjalankan perintah. Artinya rbenv harus didefinisikan secara langsung dalam skrip yang sama.

Masalah selanjutnya adalah karena perintah shell tidak memiliki status dari sudut pandang yang memungkinkan. Artinya, tidak akan ada pemeriksaan otomatis apakah versi Ruby ini sudah terinstal atau belum. Kita dapat melakukannya sendiri:

- name: Install ruby
  become_user: "{{ user }}"
  shell: |
    export PATH="${HOME}/.rbenv/bin:${PATH}"
    eval "$(rbenv init -)"
    if ! rbenv versions | grep -q {{ ruby_version }}
      then rbenv install {{ ruby_version }} && rbenv global {{ ruby_version }}
    fi
  args:
    executable: /bin/bash

Yang tersisa hanyalah menginstal bundler:

- name: Install bundler
  become_user: "{{ user }}"
  shell: |
    export PATH="${HOME}/.rbenv/bin:${PATH}"
    eval "$(rbenv init -)"
    gem install bundler

Dan sekali lagi, tambahkan peran kita ruby_rbenv ke buku pedoman utama.

File bersama.

Secara umum, penyiapan dapat diselesaikan di sini. Selanjutnya, yang tersisa hanyalah menjalankan capistrano dan itu akan menyalin kode itu sendiri, membuat direktori yang diperlukan dan meluncurkan aplikasi (jika semuanya dikonfigurasi dengan benar). Namun, capistrano seringkali memerlukan file konfigurasi tambahan, seperti database.yml ΠΈΠ»ΠΈ .env Mereka dapat disalin seperti file dan template untuk nginx. Hanya ada satu kehalusan. Sebelum menyalin file, Anda perlu membuat struktur direktori untuk file tersebut, seperti ini:

# Copy shared files for deploy
- name: Ensure shared dir
  become_user: "{{ user }}"
  file:
    path: "{{ app_path }}/shared/config"
    state: directory

kami hanya menentukan satu direktori dan kemungkinan akan secara otomatis membuat direktori induk jika perlu.

Gudang yang Mungkin

Kita telah menemukan fakta bahwa variabel dapat berisi data rahasia seperti kata sandi pengguna. Jika sudah Anda buat .env file untuk aplikasi, dan database.yml maka pasti ada lebih banyak lagi data penting seperti itu. Akan lebih baik untuk menyembunyikannya dari pengintaian. Untuk tujuan ini digunakan brankas yang memungkinkan.

Mari buat file untuk variabel /ansible/vars/all.yml (di sini Anda dapat membuat file berbeda untuk grup host berbeda, seperti di file inventaris: produksi.yml, staging.yml, dll).
Semua variabel yang harus dienkripsi harus ditransfer ke file ini menggunakan sintaks yml standar:

# System vars
user_password: 123qweasd
db_password: 123qweasd

# ENV vars
aws_access_key_id: xxxxx
aws_secret_access_key: xxxxxx
aws_bucket: bucket_name
rails_secret_key_base: very_secret_key_base

Setelah itu file ini dapat dienkripsi dengan perintah:

ansible-vault encrypt ./vars/all.yml

Biasanya, saat mengenkripsi, Anda perlu menyetel kata sandi untuk dekripsi. Anda dapat melihat apa yang ada di dalam file setelah memanggil perintah ini.

Melalui ansible-vault decrypt file dapat didekripsi, dimodifikasi, dan kemudian dienkripsi lagi.

Anda tidak perlu mendekripsi file agar berfungsi. Anda menyimpannya terenkripsi dan menjalankan pedoman dengan argumen --ask-vault-pass. Ansible akan meminta kata sandi, mengambil variabel, dan menjalankan tugas. Semua data akan tetap terenkripsi.

Perintah lengkap untuk beberapa grup host dan brankas yang memungkinkan akan terlihat seperti ini:

ansible-playbook -i inventory ./playbook.yml -l "staging" --ask-vault-pass

Namun saya tidak akan memberi Anda teks lengkap tentang pedoman dan peran, tulislah sendiri. Karena mungkin memang seperti itu - jika Anda tidak memahami apa yang perlu dilakukan, maka hal itu tidak akan berhasil untuk Anda.

Sumber: www.habr.com

Tambah komentar