Friday, April 07, 2023

Cloud Init Modules

 Cloud-init modules, also known as "cloud-config modules," help automate the provisioning and configuration of servers. When provisioning a server for a Ruby on Rails application, you can use various cloud-init modules to set up your server environment, install required packages, and configure your application. Here are some useful cloud-init modules to consider:


package_upgrade: This module upgrades all packages on the system to their latest versions. It's useful for ensuring that the server starts with the latest security updates and package fixes.


package_upgrade: true



packages: This module installs a list of specified packages. For a Rails application, you may need to install packages such as Ruby, Node.js, Yarn, and a database server (e.g., PostgreSQL or MySQL).



packages:

  - ruby

  - nodejs

  - yarn

  - postgresql

  - postgresql-contrib



users: This module creates and configures system users. You might want to create a dedicated user for your Rails application.


users:

  - name: deploy

    groups: sudo

    shell: /bin/bash

    sudo: ['ALL=(ALL) NOPASSWD:ALL']

    ssh-authorized-keys:

      - <your_public_ssh_key>



write_files: This module writes content to specified files. You can use it to create configuration files, such as the Rails database.yml, environment files, or any other required configuration files.



write_files:

  - path: /home/deploy/my_app/shared/config/database.yml

    owner: deploy:deploy

    content: |

      production:

        adapter: postgresql

        encoding: unicode

        database: my_app_production

        pool: 5

        username: deploy

        password: mysecretpassword



runcmd: This module runs specified shell commands. It can be used to clone your Rails application repository, set up the database, run bundler, precompile assets, and start the Rails server.



runcmd:

  - sudo -u deploy -H git clone <your_app_repository> /home/deploy/my_app/current

  - sudo -u deploy -H bundle install --deployment --without development test --path /home/deploy/my_app/shared/bundle

  - sudo -u deploy -H yarn install --check-files --production

  - sudo -u deploy -H RAILS_ENV=production bundle exec rake db:create db:migrate

  - sudo -u deploy -H RAILS_ENV=production bundle exec rake assets:precompile

  - sudo -u deploy -H systemctl enable my_app

  - sudo -u deploy -H systemctl start my_app


These are just some examples of cloud-init modules that you can use to provision a server for your Ruby on Rails application. The specific modules and configurations will depend on your application's requirements and your chosen server environment.




To use environment variables for the database username and password in the database.yml file, you can utilize the ERB (Embedded Ruby) syntax. Here's an example:



production:

  adapter: postgresql

  encoding: unicode

  database: my_app_production

  pool: 5

  username: <%= ENV['DB_USERNAME'] %>

  password: <%= ENV['DB_PASSWORD'] %>


In this example, the DB_USERNAME and DB_PASSWORD environment variables are used to set the username and password for the PostgreSQL database connection.


Before running your Rails application, make sure to set these environment variables in your server environment. You can do this in several ways:


Set the environment variables in your server's environment or user's .bashrc or .bash_profile file:


export DB_USERNAME=my_db_user

export DB_PASSWORD=my_db_password



If you're using a process manager like systemd or Supervisor, you can set the environment variables in the service configuration file.

For example, with systemd, you can create a service file /etc/systemd/system/my_app.service:



[Unit]

Description=My Rails App


[Service]

User=deploy

WorkingDirectory=/home/deploy/my_app/current

Environment="DB_USERNAME=my_db_user"

Environment="DB_PASSWORD=my_db_password"

ExecStart=/bin/bash -lc 'bundle exec puma -C config/puma.rb'

Restart=always


[Install]

WantedBy=multi-user.target



If you're using a tool like dotenv or Figaro, you can set environment variables in your Rails app using a configuration file such as .env or config/application.yml. These files should not be added to your version control system.

For example, with the dotenv gem, create a .env file in your Rails app root directory:



DB_USERNAME=my_db_user

DB_PASSWORD=my_db_password



Don't forget to add the dotenv gem to your Gemfile and load it in the config/application.rb file:



# Gemfile

gem 'dotenv-rails', groups: [:development, :test]


# config/application.rb

require 'dotenv/load'



These are just a few methods for setting environment variables for your Rails application. Choose the one that best suits your deployment strategy and server environment.






To use environment variables for the database username and password in the database.yml file within the cloud-init configuration, you can use the ERB (Embedded Ruby) syntax and add the runcmd module to export the environment variables. Here's the revised cloud-init configuration:




write_files:

  - path: /home/deploy/my_app/shared/config/database.yml

    owner: deploy:deploy

    content: |

      production:

        adapter: postgresql

        encoding: unicode

        database: my_app_production

        pool: 5

        username: <%= ENV['DB_USERNAME'] %>

        password: <%= ENV['DB_PASSWORD'] %>


runcmd:

  - export DB_USERNAME=deploy

  - export DB_PASSWORD=mysecretpassword



However, keep in mind that this method of setting environment variables using runcmd is temporary and only applies to the current shell session. If you want to persist these variables for the deploy user, you should add them to the user's .bashrc or .bash_profile:



write_files:

  - path: /home/deploy/.bashrc

    owner: deploy:deploy

    append: true

    content: |

      export DB_USERNAME=deploy

      export DB_PASSWORD=mysecretpassword


  - path: /home/deploy/my_app/shared/config/database.yml

    owner: deploy:deploy

    content: |

      production:

        adapter: postgresql

        encoding: unicode

        database: my_app_production

        pool: 5

        username: <%= ENV['DB_USERNAME'] %>

        password: <%= ENV['DB_PASSWORD'] %>


This will add the environment variables to the .bashrc file of the deploy user, making them available for the Rails application.