Restarting Unicorn13:05 with Jay McGavren
Having to restart Unicorn manually after each deploy would be a pain. Let's add a Capistrano task to automate this.
If we edit
config/unicorn_init.sh, we'll see
PID=$APP_ROOT/tmp/pids/unicorn.pid. The process ID file, which is needed to restart the Unicorn process, is in the
guestbook/current/ directory, which gets overwritten on each deploy. We need to instead store it in the
shared/ directory, which is preserved between deploys.
Connect to your server via
ssh and run:
mkdir -p ~/guestbook/shared/tmp/pids/
On your development machine, in
append :linked_dirs, "tmp/pids"
From your development terminal:
bundle exec cap production deploy
Having to restart manually after each deploy is a pain, though. Let's create a task. Create
namespace :deploy do desc "Restart Unicorn" task :restart do on roles(:app) do execute "sudo /home/deploy/guestbook/current/config/unicorn_init.sh restart" # ^^^ Depending on your environment settings you may find using # "restart" as an argument to unicorn_init.sh doesn't reload your app's # code. If that's the case, try using "upgrade" instead of "restart". end end end after "deploy:finishing", "deploy:restart"
If we run
bundle exec cap production deploy:restart, we'll see
no tty present and no askpass program specified. We need to edit the "sudoers" file for our
Connect to your server via
ssh and run:
sudo visudo -f /etc/sudoers.d/deploy
If you don't already have that file, see our App Deployment Accounts workshop to create one.
Add a line to allow
unicorn_init.sh to run without a password:
deploy ALL=(ALL:ALL) ALL # Must be AFTER above line deploy ALL=NOPASSWD: /home/deploy/guestbook/current/config/unicorn_init.sh
bundle exec cap production deploy:restart should work now. And running
bundle exec cap production deploy should automatically restart Unicorn after the deployment.
We rely on the unicorn_init.sh file to start, stop, and restart our server. 0:00 But if we go and look at that file in our editor, we'll see that it is writing 0:06 a process ID out to a pid file with n or 0:10 f root directory which is set to home, deploy, guestbook, current. 0:14 Now if you recall, the current directory gets overwritten on each deploy, 0:19 which means that process ID file will be as well, and 0:23 we won't be able to restart our servers successfully. 0:25 We need to instead store this process ID file on the shared directory and 0:28 link it in to the current directory. 0:32 So here on the server I'm going to create 0:35 the process ID director that we need within the shared directory. 0:39 So I'm gonna call the make directory command. 0:43 I'm going to pass the -p command line flag which will 0:46 create any missing parent directories for this directory I'm creating. 0:50 I'm going to create it within the home directory, guestbook subdirectory, 0:55 shared subdirectory, and then I'll create the tmp/pids subdirectory. 0:59 So that sets up the directory we need within the shared subdirectory, but 1:06 both unicorn_init.sh and unicorn.rb are set up to look for 1:10 the file in the guestbook current directory. 1:14 So we're going to need to link that process IDs directory into the current 1:17 directory. 1:21 And just like with the RBM shared file, we can do this from the config deploy file. 1:22 The linked_files array variable is used to maintain a list of files 1:29 that are gonna be linked from a shared directory into the current directory. 1:34 And similarly, there's a linked directories variable. 1:37 That sets up an array of directory paths that will be 1:41 symbolically linked from the shared directory into the current directory. 1:46 So just like above I'm going to call the append method. 1:51 I'll pass a symbol with the name of the linked directories variable. 1:54 Linked_dirs. 2:00 And I'm going to pass it a string with 2:02 the path of the directory we want to link, tmp/pids. 2:05 By the way you may also want to later look into adding a logged directories 2:10 to link directory so that your logs are preserved between deployments as well. 2:14 I'm not going to do that here though, let's save and close this. 2:18 And just like before, we need to do a deployment to create this symbolically, 2:22 so I'm gonna exit out of the server and run bundle exec cap production deploy. 2:29 And just as it creates a symbolic link with our rbenv-vars file from 2:41 the shared directory to the current directory, 2:46 it'll also create a symbolic link for our process IDs directory. 2:49 And now if we connect back to the server and 2:54 list out the guestbook/current/ 2:59 tmp directory in long format coming at the list all files in long format 3:06 command line flag there. 3:10 We'll see that the pids subdirectory here is actually a symbolic link 3:13 to home/deploy/guestbook/shared/tmp/pids. 3:18 Any process files that get created within the pids directory will actually be 3:22 symbolically linked back to the shared directory now and 3:26 preserved between deploys. 3:29 So now we should be able to try reissuing our restart command. 3:31 And unfortunately we have hit an error saying master fail to 3:35 start check the standard error log for details. 3:40 Let's take a look at that. 3:44 So I'm gonna look at the contents of the guestbook, 3:47 current directory, unicorn sub directory and the unicorn.log file. 3:50 What I'm seeing here is an error saying that the address is already in use. 3:57 Presumably, that's because some prior unicorn process is still running. 4:02 What likely happened is that the process ID 4:06 file got wiped out because we didn't have it set properly yet. 4:10 And so, our unicorn init script wasn't able to shut down that process ID. 4:13 We can look for unicorn processes that are still running manually by running 4:21 the ps command and we can pass at the aux flags. 4:26 Basically that'll list all the processes that are running in extended format, so 4:31 that we can see all their details. 4:35 And then I'm going to pass that output to the grep command which will print only 4:37 lines that match up given string. 4:42 I only want to see lines that are for a process named unicorn. 4:44 So I'm gonna say grep unicorn. 4:49 And we do see several previous unicorn processes here that are running. 4:52 The one I'm interested in here is the unicorn master process. 4:57 And it's got its process ID printed here. 5:01 So what I'm going to do is I'm going to send it a signal using the kill command. 5:03 The kill command takes a flag with the signal you wanna send to it. 5:10 I'm going to send the quit signal with dash quit and 5:13 then I'll type the process ID that I wanna send the signal to, that's 25817 in this 5:17 case, it's going to be a different process ID on each server. 5:22 I'll send that signal and I'll re-run my ps aux command, 5:28 just to make sure no uniform processes are still running. 5:32 It looks like they aren't. 5:35 Alright, let's try running that unicorn_init.sh 5:36 restart command one more time. 5:39 And we don't see an arrow this time. 5:42 Let's visit our page and see if it loaded successfully. 5:44 Looks like the front page loaded, and I'm able to create a signature successfully. 5:49 Looks like everything is running properly. 5:54 Now obviously it would be a pain to have to run this unicorn_init.sh restart 5:56 each time we did the deploy. 6:01 So let's see if we can set up a task to automatically restart 6:03 unicorn after each deployment, so here in my editor back on my development 6:07 machine I'm going to create a file to hold the new Capistrano task. 6:11 Like everything else that's going to go in lib Capistrano tasks and 6:15 I'll create a new file. 6:19 Since this task is going to restart our unicorn server on each deployment I'm 6:21 going to name it deploy_restart.rake. 6:25 Remember, needs a .rake extension, not .rb. 6:30 We're going to want this task to live within the deploy namespace, 6:34 so I'm going to call namespace, passive assemble deploy. 6:37 And then give it a block in which we'll create a task. 6:43 This task description is going to be restart unicorn. 6:47 And then for the actual test definition we'll call the task method and 6:54 give it a task name restart. 6:59 This will appear in the task list as deploy:restart. 7:02 I give task of block with the statements it's going to need to execute. 7:06 We're only going to want this task to run on application servers, so 7:13 I'm going to say on rules(:app) And then give that a block. 7:18 And then finally we're going to call the execute method, and 7:26 give it a command to execute over SSH. 7:30 We're going to use the second form of the execute method, 7:33 which takes just a single string. 7:36 And that string will be ran on the remote server verbatim. 7:39 So I'm going to execute our unicorn_init script just like we've been doing 7:42 in the shell. 7:46 I'll say, sudo, 7:47 because we need administrative privileges to start a service process. 7:48 And then I'm gonna give it the full path to our unicorn_init.sh script. 7:53 That's in home/deploy/guestbook/current/config/unic- 7:57 orn_init.sh. 8:07 And I'm going to pass it the restart argument so that it restarts the server. 8:10 Depending on your environment settings you may find that 8:15 using restart doesn't work properly, and you may need to replace it with upgrade. 8:18 See the teachers' notes if you'd like more information about that. 8:23 I'm going to leave it set to restart here, however. 8:26 Okay, save our changes to the file, and let's exit out of our server, 8:30 back to our local development machine, and try running the task. 8:34 bundle exec cap production deploy:restart. 8:38 And we see an error here sudo no tty present and no askpass program specified. 8:47 This is a complicated way of saying that sudo tried to ask for a password so 8:54 that it had permission to run a program with administrative privileges. 8:58 But since we were connecting the capistrano in 9:03 that ssh it was unable to ask us for a password. 9:06 What we need to do is set up our deploy user so 9:10 that the pseudo command doesn't ask for our password when we're running 9:12 the unicorn_init.sh script so let's ssh back to our server. 9:17 And we can set up a particular command not to require a password within 9:22 the sudoers file for our deployed user. 9:26 So I'm going to run the sudo command, 9:29 because you need sudo to edit sudo permissions. 9:31 Then I'm going to run the visudo command, which will launch an editor for us. 9:36 I'm going to pass it the -f command line flag, 9:42 which lets me specify a file I wanna edit. 9:45 And I'm going to specify that I want to edit the /etc/sudoers.d/deploy file, 9:48 which we set up in a previous workshop. 9:57 Hit Enter, and we'll need to enter our password, 10:00 since we're running a sudo command. 10:02 Up here we see a preexisting line, 10:06 which allows our deploy user on any server to run any command as any user. 10:09 We're going to add a second line, and it's important that this line appear 10:16 after the above line so that it doesn't override it. 10:19 This is going to affect the deploy user It's going to apply on all servers, 10:22 and we're going to specify that no password, NOPASSWD, 10:28 not PASSWORD, but PASSWD, 10:33 it's an abbreviation. 10:37 And we're going to specify the particular command that no password should be 10:44 required for. 10:47 We're going to give it full path to our unicorn_init .sh script. 10:48 So /home/deploy/guestbook/current/config/uni- 10:52 corn_init.sh. 11:00 As always, we hit Ctrl+O to write the file out, and Ctrl-X to exit. 11:07 Now let's exit back to our development machine and 11:13 try running our deploy restart task again. 11:16 And this time it runs unicorn_init.sh 11:20 restart without any errors because it didn't have to ask for a password. 11:23 So we've got a working deploy restart task that will restart our unicorn server for 11:27 us, but we want it to run automatically after each deployment. 11:32 So let's go back to our editor here in the deploy restart.rake file. 11:36 And just as in our deploy_initial.rake file, we set up our 11:40 create_db task to run before the deploy:migrate task. 11:45 We're going to call a different capistrano method named after. 11:50 We're going to set our deploy:restart task up to run automatically after 11:56 the deploy:finishing task, 12:00 which is run automatically each time a deployment finishes. 12:04 So we say deploy:finishing, deploy:restart. 12:08 So now, back in our development shell. 12:17 Let's try running in ordinary deployment and 12:19 see if our restart task runs automatically afterwards. 12:22 So bundle, exec, cap, production, deploy and 12:25 no restart we're just gonna kick off an ordinary deploy task. 12:30 And just before our deploy finishes our deploy restart task gets invoked and 12:43 it calls unicorn_init.sh restart. 12:48 Let's revisit the page in our web browser and make sure that its running properly. 12:51 Looks like everything's working properly. 13:02
You need to sign up for Treehouse in order to download course files.Sign up