This is the part 2 of our service deployment walkthrough.
See also: Part 1 — Service accounts, sudo capabilities
In the first part, we’ve seen how to create an user account for the service, a group to put users with access to the service into, and sudo capabilities to allow full control on the service account, some control as root to interact with systemd or another service manager.
Deploy an application through package
If your application is packaged or you package it, something we recommend hearthily, you can simply the pkg.installed state.
For example if you wish to deploy with this state configuration:
1 2 3 4 5 6 |
odderon_packages: pkg: - installed - pkgs: - darkbot - darkbot-backup-manager |
If you only have one application you installed, you can omit pkgs, it will then take the state name:
1 2 |
darkbot: pkg.installed |
If you want to force the last version to be reinstalled when you run again the state, you can instead use pkg.latest:
1 2 |
darkbot: pkg.latest |
Salt can then take care of your upgrade process.
Deploy an application fetching and building it
In this sample, we’ll fetch the source code from the last version of the production
branch of a Git repository cloned at /usr/local/src/darkbot
, and we’ll install the software to /opt/odderon
. To use /opt
will allow us to perform an installation process running as a non privileged user.
Fetch the source code
Sometimes, you want a workflow to fetch, build, install, to have a better control on the compilation. Docker image creators tend to like to automate build processes.
For that, you need two things:
- A directory where to clone the software
- To actually clone the repository
A same Salt state can call several functions, here one from file to create a directory (file.directory) and one from git to clone (git.latest):
1 2 3 4 5 6 7 8 9 10 11 |
darkbot_repo: file.directory: - name: /usr/local/src/darkbot - user: odderon - group: nasqueron-irc - dir_mode: 755 git.latest: - name: https://devcentral.nasqueron.org/source/darkbot.git - branch: production - target: /usr/local/src/darkbot - user: odderon |
We’ve reused the user and group created in previous part.
To clone the repository, we recommend to do the clone from a source you can trust (e.g. PHP provides GPG signed packages) or better, a source you control.
Note it’s currently not possible to call two functions from the same module, e.g. two git or two file wouldn’t work.
If you automate the upgrade process (something best to do only if your CI/CD infrastructure tests the Salt deployment), provide your deployers a quick way to stop the update process.
For example, you can provide a lock file in the application directory (here /opt/odderon):
1 2 3 4 5 6 7 8 |
…: … git.latest: - name: https://devcentral.nasqueron.org/source/darkbot.git - branch: production - target: /usr/local/src/darkbot - user: odderon - unless: test -f /opt/odderon/LOCKED |
If the file exists, state will be skipped, so it’s as simple as touch /opt/odderon/LOCKED
to pause deployment, rm /opt/odderon/LOCKED
to resume it. SaltStack has a good documentation about requisites, requisites not always intuitive.
Compile
Let’s start with a simple case where you only have one command to write to configure, compile, install, for example here: ./build.sh --with-sleep=0 --with-add=0 --with-del=0 --with-random=0 --destdir=/opt/odderon
.
For that, you only need cmd.run:
1 2 3 4 5 6 |
darkbot_build: cmd.run: - name: ./build.sh - args: "--with-sleep=0 --with-add=0 --with-del=0 --with-random=0 --destdir=/opt/odderon" - cwd: /usr/local/src/darkbot - runas: odderon |
The cwd
parameter allows to change the working directory (cd /usr… ; ./build.sh…) and runas
to run the command as another user than root.
If you don’t have such script available, just create it.
Salt allows to deploy a custom script before to run it in one step with the cmd.script command:
1 2 3 4 5 6 |
darkbot_build: cmd.script: - source: salt://roles/shellserver/odderon/files/build.sh - args: "--with-sleep=0 --with-add=0 --with-del=0 --with-random=0" - cwd: /usr/local/src/darkbot - runas: odderon |
The roles/shellserver/odderon/files/build.sh
file will be copied on the server, and run, and yes you can also send arguments to the script like with cmd.run.
This process isn’t useful if Git failed, so we can require another state succeeded:
1 2 3 4 5 6 7 8 |
darkbot_build: cmd.script: - source: salt://roles/shellserver/odderon/files/build.sh - args: "--with-sleep=0 --with-add=0 --with-del=0 --with-random=0" - cwd: /usr/local/src/darkbot - runas: odderon - require: - git: darkbot_repo |
The same process can be used to provide the service configuration. For example, to copy a hierarchy of files from your Salt root directory to the server:
1 2 3 4 5 6 |
darkbot_configuration: file.recurse: - name: /opt/odderon/dat - source: salt://roles/shellserver/odderon/files/dat - dir_mode: 770 - file_mode: 640 |
The 770 directory mode will allow the service and the deployers to access it, files by default read only for deployers to encourage to use Salt to edit them.
By the way, you probably also want a warning like this:
1 2 3 4 5 6 7 8 9 |
# <auto-generated> # This file is managed by our rOPS repository # and deployed through SaltStack. # # Changes to this file may cause incorrect behavior # and will be lost if the state is redeployed. # # Source directory: roles/shellserver/odderon/files/dat # </auto-generated> |
It’s then clear when you’re on the production server a file opened is managed.
Upgrade the code
So, what can you do with that?
First, it can provision your service to a new server, but you can also use it for updat. For example, if you’ve your states in roles/shellserver/odderon/init.sls, you can upgrade with:
salt eglide state.apply roles/shellserver/odderon
It will then upgrade your package or fetch the latest Git commit and recompile your code.
If you compile manually, note the build script doesn’t especially need a clean step. For example, if you use a Makefile, make will detect your file has been modified (looking the timestamp) and so should be upgraded.
Create a service
Thanks to Sandlayth to have prepared the Salt configuration for this part.
If your application doesn’t provide a service, it’s valuable to create one.
Two steps are needed: deploy the service file, ensure the service runs. For systemd, a third step is needed to force reload configuration.
The first part is service manager dependant, the second part is service manager agnostic.
1 2 3 4 5 |
odderon_service: file.managed: - name: /usr/local/etc/rc.d/odderon - source: salt://roles/shellserver/odderon/files/odderon.rc - mode: 0755 |
We told you there is an extra step for systemd. This one is tricky: as this is a command to refresh an application knowledge, that’s not something we can declare and check, so it’s not available as a state. SaltStack also allows to run commands, and provide modules for that. For example, you can do salt eglide service.force_reload odderon
(see systemd module doc, right menu offers the same for other systems).
1 2 3 4 5 6 7 8 9 10 |
odderon_service: file.managed: - name: /etc/systemd/system/odderon.service - source: salt://roles/shellserver/odderon/files/odderon.service - mode: 0644 module.run: - name: service.force_reload - m_name: odderon - onchanges: - file: odderon_unit |
Parameters for the module you run are directly put after the name. But here service.force_reload
has also a name
parameter. To disambiguate, you prepend m_
and get m_name
.
There is currently in Salt a work of progress to abstract more the services.
Finally, whatever the service manager, you want to ensure the service runs:
1 2 3 4 5 6 |
odderon_running: service.running: - name: odderon - enable: true - watch: - module: odderon_service |
The enable
parameter is useful if you use a systemd-like service, as the service must be explicitly enabled to be automatically launched at server start time.
One thought on Deploy a darkbot or a simple generic service with SaltStack (part 2)