📜 ⬆️ ⬇️

Autorun rails + rvm + unicorn + nginx on FreeBSD

First, you need to say “thank you” to the author of this guide . Without him, I would not have sat down for writing this post for a long time: a bunch of problems would have to be solved on my own. However, in my case, the situation was slightly different (not Debian, but FreeBSD), and the unicorn autostart question remained open. I also didn’t pretend to elegance on the Internet, I also didn’t pretend: to do a service on a web application - moveton. At FreeBSD, this problem is solved at first glance simply by creating “metaservices” that allow you to run more than one instance (as an example, FreeBSD jails). However, as is often the case, there are nuances ...

rc.d

Since all rc.d-configs are shell scripts, you can not be limited to the /etc/rc.conf file and its companion /etc/rc.conf.local , but place the fragments in the /etc/rc.conf.d and /usr/local/etc/rc.conf.d The only recommendation is that the files should be named the same as the services using them. This allows you to avoid turning the configuration files into unreadable monsters from more than a hundred lines, in which you will not understand without grep. The problem is different: if the service has several instances, ALL their settings should formally be in the same file (the name of which, I remind, coincides with the name of the service). To solve this problem, you need to understand how the service startup scripts work.
Usually this process is described approximately as follows: "When the system is started, the script runs in /etc/rc . It reads the settings from the /etc/rc.conf file (as well as /etc/rc.conf.local - if there is one) ..." And no! Instead, it includes the /etc/rc.subr file, which defines some auxiliary functions and also includes the system configuration files:
 ... if ${_rc_conf_loaded:-false}; then : else if [ -r /etc/defaults/rc.conf ]; then debug "Sourcing /etc/defaults/rc.conf" . /etc/defaults/rc.conf source_rc_confs elif [ -r /etc/rc.conf ]; then debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)." . /etc/rc.conf fi _rc_conf_loaded=true fi if [ -f /etc/rc.conf.d/"$_name" ]; then debug "Sourcing /etc/rc.conf.d/${_name}" . /etc/rc.conf.d/"$_name" fi ... 

In turn, the /etc/defaults/rc.conf file contains the following code:
 ... rc_conf_files="/etc/rc.conf /etc/rc.conf.local" ... ############################################################## ### Define source_rc_confs, the mechanism used by /etc/rc.* ## ### scripts to source rc_conf_files overrides safely. ## ############################################################## if [ -z "${source_rc_confs_defined}" ]; then source_rc_confs_defined=yes source_rc_confs () { local i sourced_files for i in ${rc_conf_files}; do case ${sourced_files} in *:$i:*) ;; *) sourced_files="${sourced_files}:$i:" if [ -r $i ]; then . $i fi ;; esac done } fi 

After downloading all the settings, a list of system services is compiled, and a launch script is called for each service, regardless of whether it is enabled or not. Therefore, it is strongly recommended not to place user services files in the /etc/rc.d directory - this will increase the system boot time. For user services, there is a directory /usr/local/etc/rc.d - the scripts in it are called up last, when the main system is already configured and ready to go. But the real black magic begins further: each of these scripts again includes the /etc/rc.subr script loading the variables relating to it. And this makes it possible to make even more modular configuration files: just include a code like the following in the main file in the /etc/rc.conf.d directory (using the unicorn example as an example):
 unicorn_enable="YES" unicorn_profiles="" for p in $(grep -rlE '^unicorn_[0-9a-zA-Z]+_enabled="[Yy][Ee][Ss]"$' /usr/local/etc/unicorn.d); do bn=$(basename $p) if [ -n "$unicorn_profiles" ]; then unicorn_profiles="$unicorn_profiles $bn" else unicorn_profiles="$bn" fi . $p done 


Unicorn

First of all, we'll put sudo - it is much more convenient than “sculpt” a command to run through su, prompting for shell injection.
 cd /usr/ports/security/sudo && make install clean 

We will also put a utility called portmaster - this will facilitate the further process:
 cd /usr/ports/ports-mgmt/portmaster && make install clean 

We will install the rest of the software with its help:
 LN='ln -f' portmaster devel/bison textproc/libxml2 textproc/libxslt textproc/diffutils devel/gmake security/openssl devel/automake devel/git devel/subversion shells/bash 

For the lazy - setting the default environment:
 portmaster lang/ruby19 sysutils/rubygem-bundler www/rubygem-unicorn 

A description of the next steps can be found in the original article, and we move on to the next part - installing all this stuff as a service.

In order to be able to manage multiple instances of the service, the following code must be included in the startup script:
 is_unicorn_profile() { local profile for profile in $unicorn_profiles; do if [ "$profile" = "$1" ]; then return 0 fi done return 1 } if [ -n "${unicorn_profiles}" ]; then if [ -n "$2" ]; then profile="$2" if ! is_unicorn_profile $profile; then echo "$0: no such profile defined in unicorn_profiles." exit 1 fi eval unicorn_socket=\${unicorn_${profile}_socket:-"/tmp/${name}-${profile}.sock"} eval unicorn_config=\${unicorn_${profile}_config} eval unicorn_dir=\${unicorn_${profile}_dir} eval unicorn_flags=\${unicorn_${profile}_flags:-"${unicorn_flags}"} eval unicorn_environment=\${unicorn_${profile}_environment:-"${unicorn_environment}"} eval unicorn_rails=\${unicorn_${profile}_rails:-"${unicorn_rails}"} eval unicorn_user=\${unicorn_${profile}_user:-"${unicorn_user}"} eval unicorn_procname=\${unicorn_${profile}_procname:-"${unicorn_procname}"} eval unicorn_bundler=\${unicorn_${profile}_bundler:-"${unicorn_bundler}"} eval unicorn_rvm=\${unicorn_${profile}_rvm:-"${unicorn_rvm}"} eval unicorn_ruby=\${unicorn_${profile}_ruby:-"${unicorn_ruby}"} if checkyesno unicorn_rvm; then unicorn_procname="~${unicorn_user}/.rvm/rubies/ruby-${unicorn_ruby}/bin/ruby" fi elif [ -n "$1" ]; then for profile in ${unicorn_profiles}; do echo "Processing ${name} profile: ${profile}" $0 $1 ${profile} done exit 0 fi fi 

Using RVM creates a problem: for different applications it is necessary to adjust the environment. You can, of course, after starting each instance, reinitialize the environment, but it is easier to use an auxiliary script:
 if checkyesno unicorn_rvm; then if [ -d "~${unicorn_user}/.rvm/${unicorn_ruby}" ]; then /usr/local/bin/sudo -u $unicorn_user /usr/bin/env SHELL=/usr/local/bin/bash CDPATH=. /usr/local/bin/unicorn-wrapper ${unicorn_ruby} $(basename ${command}) ${command_args} rc=$? else echo "Ruby version ${unicorn_ruby} not found by RVM for user ${unicorn_user}" rc=1 fi else /usr/local/bin/sudo -u $unicorn_user ${command} ${command_args} rc=$? fi 

In the process of testing, it turned out that if ZSH is used, it is necessary to add ZSH_VERSION="" to the list of variables to be ZSH_VERSION="" . The file /usr/local/bin/unicorn-wrapper is a simple wrapper that installs the correct version of Ruby and executes the specified command with arguments. The full version of the startup script can be found next . It is very easy to use:
 service unicorn <action> [<app>] 

Config example:
 unicorn_redmine_enabled="YES" unicorn_redmine_dir="/var/www/sites/mycoolsite.tld/redmine" unicorn_redmine_rails="NO" 

In an amicable way, it would be necessary to issue a Port Request, but so far the hands have not reached.
')
PS There is only one question left open: how to integrate this kindly with the same capistrano so that the settings do not go off when updating?

Source: https://habr.com/ru/post/166807/


All Articles