Ansible kullanarak bir Rails uygulamasını dağıtmak için bir sunucu kurma

Kısa bir süre önce sunucuyu bir Rails uygulamasını dağıtmaya hazırlamak için birkaç Ansible oyun kitabı yazmam gerekiyordu. Ve şaşırtıcı bir şekilde, adım adım ilerleyen basit bir kılavuz bulamadım. Ne olduğunu anlamadan başka birinin taktik kitabını kopyalamak istemedim ve sonunda belgeleri okuyup her şeyi kendim toplamak zorunda kaldım. Belki bu makalenin yardımıyla birisinin bu süreci hızlandırmasına yardımcı olabilirim.

Anlaşılması gereken ilk şey, ansible'ın size SSH aracılığıyla uzak sunucu(lar) üzerinde önceden tanımlanmış bir eylem listesi gerçekleştirmeniz için kullanışlı bir arayüz sağladığıdır. Burada sihir yok; bir eklenti yükleyemez ve docker, izleme ve kutudan çıkan diğer özelliklerle uygulamanızın sıfır kesinti süresiyle konuşlandırılmasını sağlayamazsınız. Bir taktik kitabı yazmak için tam olarak ne yapmak istediğinizi ve bunu nasıl yapacağınızı bilmelisiniz. Bu yüzden GitHub'un hazır taktik kitaplarından veya "Kopyala ve çalıştır, işe yarayacak" gibi makalelerden memnun değilim.

Ne gerekiyor?

Daha önce de söylediğim gibi, bir taktik kitabı yazmak için ne yapmak istediğinizi ve bunu nasıl yapacağınızı bilmeniz gerekir. Neye ihtiyacımız olduğuna karar verelim. Rails uygulaması için birkaç sistem paketine ihtiyacımız olacak: nginx, postgresql (redis, vb.). Ayrıca Ruby'nin belirli bir sürümüne ihtiyacımız var. Bunu rbenv (rvm, asdf...) aracılığıyla kurmak en iyisidir. Tüm bunları kök kullanıcı olarak çalıştırmak her zaman kötü bir fikirdir, bu nedenle ayrı bir kullanıcı oluşturmanız ve haklarını yapılandırmanız gerekir. Bundan sonra kodumuzu sunucuya yüklemeniz, nginx, postgres vb. için yapılandırmaları kopyalamanız ve tüm bu hizmetleri başlatmanız gerekir.

Sonuç olarak, eylem sırası aşağıdaki gibidir:

  1. Kök olarak oturum açın
  2. sistem paketlerini yükle
  3. yeni bir kullanıcı oluştur, hakları yapılandır, ssh anahtarı
  4. sistem paketlerini (nginx vb.) yapılandırın ve çalıştırın
  5. Veritabanında bir kullanıcı oluşturuyoruz (hemen veritabanı oluşturabilirsiniz)
  6. Yeni bir kullanıcı olarak giriş yapın
  7. Rbenv ve Ruby'yi yükleyin
  8. Paketleyiciyi takma
  9. Uygulama kodunun yüklenmesi
  10. Puma sunucusunu başlatma

Üstelik son aşamalar capistrano kullanılarak yapılabilir; en azından kutudan çıktığı haliyle kodu sürüm dizinlerine kopyalayabilir, başarılı dağıtım sonrasında sürümü bir sembolik bağlantıyla değiştirebilir, yapılandırmaları paylaşılan bir dizinden kopyalayabilir, puma'yı yeniden başlatabilir, vb. Bütün bunlar Ansible kullanılarak yapılabilir, ama neden?

Dosya yapısı

Ansible'ın katı kuralları var dosya yapısı tüm dosyalarınız için, bu nedenle hepsini ayrı bir dizinde tutmak en iyisidir. Üstelik ray uygulamasının kendisinde mi yoksa ayrı ayrı mı olacağı o kadar da önemli değil. Dosyaları ayrı bir git deposunda saklayabilirsiniz. Şahsen ben, Rails uygulamasının /config dizininde yanıtlanabilir bir dizin oluşturmayı ve her şeyi tek bir depoda saklamayı en uygun yöntem olarak buldum.

Basit Başucu Kitabı

Playbook, özel sözdizimi kullanarak Ansible'ın ne yapması gerektiğini ve nasıl yapması gerektiğini açıklayan bir yml dosyasıdır. Hiçbir şey yapmayan ilk taktik kitabını oluşturalım:

---
- name: Simple playbook
  hosts: all

Burada sadece başucu kitabımızın adının verildiğini söylüyoruz Simple Playbook ve içeriğinin tüm ana bilgisayarlar için yürütülmesi gerektiği. /ansible dizinine ismiyle kaydedebiliriz. playbook.yml ve çalıştırmayı deneyin:

ansible-playbook ./playbook.yml

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

Ansible, tüm listeyle eşleşen hiçbir ana bilgisayarı bilmediğini söylüyor. Özel bir listede yer almaları gerekir envanter dosyası.

Bunu aynı ansible dizinde oluşturalım:

123.123.123.123

Ana bilgisayarı (ideal olarak test için VPS'mizin ana bilgisayarı veya localhost'u kaydedebilirsiniz) bu şekilde belirleyip adı altında kaydediyoruz. inventory.
Ansible'ı bir invetory dosyasıyla çalıştırmayı deneyebilirsiniz:

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

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

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

Belirtilen ana bilgisayara ssh erişiminiz varsa, ansible uzak sisteme bağlanacak ve bu sistem hakkında bilgi toplayacaktır. (varsayılan GÖREV [Gerçekleri Toplama]) ve ardından yürütme hakkında kısa bir rapor verecektir (PLAY RECAP).

Varsayılan olarak bağlantı, sistemde oturum açtığınız kullanıcı adını kullanır. Büyük olasılıkla ana bilgisayarda olmayacak. Playbook dosyasında, Remote_user yönergesini kullanarak bağlanmak için hangi kullanıcının kullanılacağını belirleyebilirsiniz. Ayrıca uzaktaki bir sistem hakkındaki bilgiler çoğu zaman sizin için gereksiz olabilir ve bu bilgileri toplayarak zaman kaybetmemelisiniz. Bu görev ayrıca devre dışı bırakılabilir:

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

Başucu kitabını tekrar çalıştırmayı deneyin ve bağlantının çalıştığından emin olun. (Kök kullanıcıyı belirttiyseniz, yükseltilmiş haklar elde etmek için ayrıca make: true yönergesini de belirtmeniz gerekir. Belgelerde yazıldığı gibi: become set to ‘true’/’yes’ to activate privilege escalation. nedeni tam olarak belli olmasa da).

Belki ansible'ın Python yorumlayıcısını belirleyememesinden kaynaklanan bir hata alırsınız, o zaman bunu manuel olarak belirleyebilirsiniz:

ansible_python_interpreter: /usr/bin/python3 

Python'un nerede olduğunu şu komutla öğrenebilirsiniz. whereis python.

Sistem paketlerini yükleme

Ansible'ın standart dağıtımı, çeşitli sistem paketleriyle çalışmak için birçok modül içerir, dolayısıyla herhangi bir nedenle bash betikleri yazmamıza gerek kalmaz. Artık sistemi güncellemek ve sistem paketlerini kurmak için bu modüllerden birine ihtiyacımız var. VPS'imde Ubuntu Linux var, dolayısıyla paketleri yüklemek için kullanıyorum apt-get и bunun için modül. Eğer farklı bir işletim sistemi kullanıyorsanız o zaman farklı bir modüle ihtiyacınız olabilir (unutmayın, başlangıçta ne yapacağımızı, nasıl yapacağımızı önceden bilmemiz gerektiğini söylemiştim). Ancak sözdizimi büyük olasılıkla benzer olacaktır.

Başucu kitabımızı ilk görevlerle destekleyelim:

---
- 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

Görev tam olarak Ansible'ın uzak sunucularda gerçekleştireceği görevdir. Günlükte yürütülmesini takip edebilmemiz için göreve bir ad veriyoruz. Ve belirli bir modülün sözdizimini kullanarak ne yapması gerektiğini açıklıyoruz. Bu durumda apt: update_cache=yes - apt modülünü kullanarak sistem paketlerinin güncelleneceğini söylüyor. İkinci komut biraz daha karmaşıktır. Paketlerin bir listesini apt modülüne iletiyoruz ve bunların state olmalı presentyani bu paketleri kurun diyoruz. Benzer şekilde, onlara bunları silmelerini veya yalnızca değiştirerek güncellemelerini söyleyebiliriz. state. Rails'in postgresql ile çalışabilmesi için şu anda kurduğumuz postgresql-contrib paketine ihtiyacımız olduğunu lütfen unutmayın. Yine şunu bilmeniz ve yapmanız gerekiyor; ansible tek başına bunu yapmayacaktır.

Playbook'u tekrar çalıştırmayı deneyin ve paketlerin kurulu olup olmadığını kontrol edin.

Yeni kullanıcılar oluşturma.

Kullanıcılarla çalışmak için Ansible'ın ayrıca bir modülü vardır - kullanıcı. Bir görev daha ekleyelim (Her seferinde tamamen kopyalamamak için başucu kitabının zaten bilinen kısımlarını yorumların arkasına sakladım):

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

Yeni bir kullanıcı oluşturuyoruz, ona bir şema ve şifre belirliyoruz. Daha sonra çeşitli sorunlarla karşılaşıyoruz. Kullanıcı adlarının farklı ana bilgisayarlar için farklı olması gerekiyorsa ne olur? Ve şifreyi taktik kitabında açık metin olarak saklamak çok kötü bir fikir. Başlangıç ​​olarak kullanıcı adı ve şifreyi değişkenlere koyalım ve yazının sonuna doğru şifrenin nasıl şifreleneceğini göstereceğim.

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

Değişkenler, çift küme parantezleri kullanılarak oyun kitaplarında ayarlanır.

Envanter dosyasındaki değişkenlerin değerlerini belirteceğiz:

123.123.123.123

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

Lütfen direktife dikkat edin [all:vars] - bir sonraki metin bloğunun değişkenler (vars) olduğunu ve bunların tüm ana bilgisayarlara (tümü) uygulanabileceğini söylüyor.

Tasarımı da ilginç "{{ user_password | password_hash('sha512') }}". Mesele şu ki, ansible kullanıcıyı user_add sanki elle yapıyormuşsun gibi. Ve tüm verileri doğrudan kaydeder, bu nedenle şifreyi önceden bir karma haline dönüştürmemiz gerekir, bu komutun yaptığı da budur.

Kullanıcımızı sudo grubuna ekleyelim. Ancak bundan önce böyle bir grubun var olduğundan emin olmalıyız çünkü bunu bizim için kimse yapmayacak:

---
- 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"

Her şey oldukça basit, ayrıca apt'ye çok benzer bir sözdizimine sahip, gruplar oluşturmak için bir grup modülümüz var. Daha sonra bu grubu kullanıcıya kaydetmeniz yeterlidir (groups: "sudo").
Ayrıca bu kullanıcıya bir ssh anahtarı eklemek de faydalıdır, böylece şifre olmadan kullanarak giriş yapabiliriz:

---
- 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

Bu durumda tasarım ilginçtir. "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" — id_rsa.pub dosyasının içeriğini (adınız farklı olabilir), yani ssh anahtarının genel kısmını kopyalar ve sunucudaki kullanıcının yetkili anahtarlar listesine yükler.

rol

Kullanım yaratmaya yönelik üç görevin tümü kolaylıkla tek bir görev grubuna sınıflandırılabilir ve çok fazla büyümemesi için bu grubu ana oyun kitabından ayrı olarak saklamak iyi bir fikir olacaktır. Bu amaçla Ansible роли.
En başta belirtilen dosya yapısına göre roller ayrı bir roller dizinine yerleştirilmelidir, her rol için aynı isimde ayrı bir dizin vardır, görevler, dosyalar, şablonlar vb dizini içinde
Bir dosya yapısı oluşturalım: ./ansible/roles/user/tasks/main.yml (main, bir rol oyun kitabına bağlandığında yüklenecek ve yürütülecek ana dosyadır; diğer rol dosyaları da ona bağlanabilir). Artık kullanıcıyla ilgili tüm görevleri bu dosyaya aktarabilirsiniz:

# 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

Ana oynatma kitabında kullanıcı rolünü kullanmayı belirtmeniz gerekir:

---
- 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

Ayrıca, tüm diğer görevlerden önce sistemi güncellemek mantıklı olabilir; bunu yapmak için bloğu yeniden adlandırabilirsiniz. tasks burada tanımlanıyorlar pre_tasks.

Nginx'i ayarlama

Nginx'in zaten kurulu olması gerekir; onu yapılandırmamız ve çalıştırmamız gerekiyor. Bunu hemen rolde yapalım. Bir dosya yapısı oluşturalım:

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

Artık dosyalara ve şablonlara ihtiyacımız var. Aralarındaki fark, ansible'ın dosyaları olduğu gibi doğrudan kopyalamasıdır. Ve şablonların j2 uzantısına sahip olması gerekir ve aynı çift küme parantezlerini kullanarak değişken değerleri kullanabilirler.

Nginx'i etkinleştirelim main.yml dosya. Bunun için bir systemd modülümüz var:

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

Burada sadece nginx'in başlatılması gerektiğini söylemiyoruz (yani başlatıyoruz), aynı zamanda hemen etkinleştirilmesi gerektiğini de söylüyoruz.
Şimdi yapılandırma dosyalarını kopyalayalım:

# 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'

Ana nginx yapılandırma dosyasını oluşturuyoruz (bunu doğrudan sunucudan alabilir veya kendiniz yazabilirsiniz). Ve ayrıca sites_available dizinindeki uygulamamızın yapılandırma dosyası (bu gerekli değil ama faydalıdır). İlk durumda, dosyaları kopyalamak için kopyalama modülünü kullanırız (dosyanın /ansible/roles/nginx/files/nginx.conf). İkincisinde, değişkenlerin değerlerini değiştirerek şablonu kopyalıyoruz. Şablonun içinde olması gerekir /ansible/roles/nginx/templates/my_app.j2). Ve şöyle görünebilir:

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 }};
  ....
}

Eklere dikkat edin {{ app_name }}, {{ app_path }}, {{ server_name }}, {{ inventory_hostname }} — bunların tümü, Ansible'ın kopyalamadan önce değerleri şablona yerleştireceği değişkenlerdir. Farklı ana bilgisayar grupları için bir başucu kitabı kullanıyorsanız bu kullanışlıdır. Örneğin envanter dosyamızı ekleyebiliriz:

[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

Şimdi oyun kitabımızı başlatırsak, her iki ana bilgisayar için de belirtilen görevleri yerine getirecektir. Ancak aynı zamanda, bir hazırlama ana bilgisayarı için değişkenler, yalnızca rollerde ve oyun kitaplarında değil, aynı zamanda nginx yapılandırmalarında da üretimdekilerden farklı olacaktır. {{ inventory_hostname }} envanter dosyasında belirtilmesine gerek yoktur - bu özel yanıtlayıcı değişken ve oyun kitabının şu anda çalışmakta olduğu ana bilgisayar burada saklanır.
Birden fazla ana bilgisayar için bir envanter dosyasına sahip olmak ancak yalnızca bir grup için çalıştırmak istiyorsanız, bu aşağıdaki komutla yapılabilir:

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

Diğer bir seçenek de farklı gruplar için ayrı envanter dosyalarına sahip olmaktır. Veya çok sayıda farklı ana makineniz varsa iki yaklaşımı birleştirebilirsiniz.

Nginx kurulumuna geri dönelim. Yapılandırma dosyalarını kopyaladıktan sonra sitest_enabled'da sites_available'dan my_app.conf'a bir sembolik bağlantı oluşturmamız gerekiyor. Ve nginx'i yeniden başlatın.

... # 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

Burada her şey basit - yine oldukça standart bir sözdizimine sahip ansible modülleri. Ama bir nokta var. Her seferinde nginx'i yeniden başlatmanın bir anlamı yok. “Bunu böyle yap” gibi komutlar yazmadığımızı fark ettiniz mi, sözdizimi daha çok “bunun bu duruma sahip olması gerekir” gibi görünüyor. Ve çoğu zaman ansible tam olarak bu şekilde çalışır. Grup zaten mevcutsa veya sistem paketi zaten kuruluysa ansible bunu kontrol edecek ve görevi atlayacaktır. Ayrıca, sunucuda bulunan dosyalarla tamamen eşleşiyorsa dosyalar kopyalanmayacaktır. Bundan faydalanabilir ve nginx'i ancak yapılandırma dosyaları değiştirilmişse yeniden başlatabiliriz. Bunun için bir kayıt direktifi var:

# 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

Yapılandırma dosyalarından biri değişirse bir kopya oluşturulacak ve değişken kaydedilecektir. restart_nginx. Ve yalnızca bu değişken kaydedilmişse hizmet yeniden başlatılacaktır.

Ve tabii ki nginx rolünü ana oyun kitabına eklemeniz gerekiyor.

Postgresql'i ayarlama

Nginx'te yaptığımız gibi postgresql'i systemd kullanarak etkinleştirmemiz ve ayrıca veritabanına ve veritabanının kendisine erişmek için kullanacağımız bir kullanıcı oluşturmamız gerekiyor.
Bir rol oluşturalım /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 }}"

Envantere nasıl değişken ekleneceğini açıklamayacağım, bu zaten birçok kez yapıldı, ayrıca postgresql_db ve postgresql_user modüllerinin sözdizimi de var. Daha fazla bilgiyi belgelerde bulabilirsiniz. Buradaki en ilginç direktif become_user: postgres. Gerçek şu ki, varsayılan olarak yalnızca postgres kullanıcısı postgresql veritabanına ve yalnızca yerel olarak erişebilir. Bu yönerge, bu kullanıcı adına komutları yürütmemize olanak tanır (tabii ki erişimimiz varsa).
Ayrıca yeni bir kullanıcının veritabanına erişmesine izin vermek için pg_hba.conf dosyasına bir satır eklemeniz gerekebilir. Bu, nginx yapılandırmasını değiştirdiğimiz şekilde yapılabilir.

Ve tabii ki postgresql rolünü ana playbook'a eklemeniz gerekiyor.

Ruby'yi rbenv aracılığıyla kurmak

Ansible'ın rbenv ile çalışmaya yönelik modülleri yoktur, ancak bir git deposunun kopyalanmasıyla kurulur. Dolayısıyla bu sorun en standart dışı sorun haline geliyor. Onun için bir rol oluşturalım /ansible/roles/ruby_rbenv/main.yml ve doldurmaya başlayalım:

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

Bu amaçlarla oluşturduğumuz kullanıcı altında çalışmak için yine make_user yönergesini kullanıyoruz. Rbenv global olarak değil, ana dizinine kurulduğundan beri. Ayrıca, repo ve dest'i belirterek depoyu klonlamak için git modülünü kullanırız.

Daha sonra, rbenv init'i bashrc'ye kaydetmemiz ve orada PATH'e rbenv'i eklememiz gerekiyor. Bunun için lineinfile modülümüz var:

- 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 -)"'

O zaman ruby_build'i kurmanız gerekiyor:

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

Ve son olarak Ruby'yi kurun. Bu, rbenv aracılığıyla, yani basitçe bash komutuyla yapılır:

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

Hangi komutun neyle yürütüleceğini söylüyoruz. Ancak burada ansible'ın komutları çalıştırmadan önce bashrc'nin içerdiği kodu çalıştırmadığı gerçeğiyle karşılaşıyoruz. Bu, rbenv'in doğrudan aynı komut dosyasında tanımlanması gerektiği anlamına gelir.

Bir sonraki sorun, yanıtlanabilir bir bakış açısından kabuk komutunun hiçbir durumunun olmamasından kaynaklanmaktadır. Yani Ruby'nin bu sürümünün kurulu olup olmadığı otomatik olarak kontrol edilmeyecektir. Bunu kendimiz yapabiliriz:

- 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

Geriye kalan tek şey paketleyiciyi yüklemek:

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

Ve yine ruby_rbenv rolümüzü ana taktik kitabına ekleyin.

Paylaşılan dosyalar.

Genel olarak kurulum burada tamamlanabilir. Daha sonra geriye kalan tek şey capistrano'yu çalıştırmaktır ve kendisi kodu kopyalayacak, gerekli dizinleri oluşturacak ve uygulamayı başlatacaktır (eğer her şey doğru yapılandırılmışsa). Ancak capistrano sıklıkla aşağıdakiler gibi ek yapılandırma dosyaları gerektirir: database.yml veya .env Tıpkı nginx dosyaları ve şablonları gibi kopyalanabilirler. Tek bir incelik var. Dosyaları kopyalamadan önce, onlar için şöyle bir dizin yapısı oluşturmanız gerekir:

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

yalnızca bir dizin belirleriz ve gerekirse ansible otomatik olarak ana dizinleri oluşturur.

Ansible Kasası

Değişkenlerin kullanıcının şifresi gibi gizli verileri içerebildiği gerçeğiyle zaten karşılaştık. Eğer yarattıysanız .env Başvuru dosyası ve database.yml o zaman bu türden daha fazla kritik veri olması gerekir. Onları meraklı gözlerden saklamak iyi olurdu. Bu amaçla kullanılır yanıtlanabilir kasa.

Değişkenler için bir dosya oluşturalım /ansible/vars/all.yml (burada tıpkı envanter dosyasında olduğu gibi farklı ana bilgisayar grupları için farklı dosyalar oluşturabilirsiniz: Production.yml, staging.yml, vb.).
Şifrelenmesi gereken tüm değişkenler, standart yml sözdizimi kullanılarak bu dosyaya aktarılmalıdır:

# 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

Bundan sonra bu dosya şu komutla şifrelenebilir:

ansible-vault encrypt ./vars/all.yml

Doğal olarak, şifreleme sırasında şifre çözme için bir şifre belirlemeniz gerekecektir. Bu komutu çağırdıktan sonra dosyanın içinde ne olacağını görebilirsiniz.

Vasıtasıyla ansible-vault decrypt dosyanın şifresi çözülebilir, değiştirilebilir ve ardından tekrar şifrelenebilir.

Çalışmak için dosyanın şifresini çözmenize gerek yoktur. Şifrelenmiş olarak saklarsınız ve oyun kitabını argümanla çalıştırırsınız --ask-vault-pass. Ansible şifreyi isteyecek, değişkenleri alacak ve görevleri yürütecektir. Tüm veriler şifreli kalacaktır.

Birkaç ana bilgisayar grubu ve yanıtlanabilir kasa için tam komut şuna benzer:

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

Ama size taktik kitaplarının ve rollerin tam metnini vermeyeceğim, kendiniz yazın. Çünkü ansible böyledir; eğer ne yapılması gerektiğini anlamıyorsanız, o bunu sizin için yapmaz.

Kaynak: habr.com

Yorum ekle