We, at Yakaz, use Erlang to run several services of Yakaz.com. This language supports a powerful feature: hot upgrade of a running service (sometimes called "live upgrade"). It means it has the ability to reload configuration and upgrade applications without shutting down the service. This is a greatly appreciated feature, because it allows us to prevent any service disruption: users won't experience half-loaded classifieds search results, loss of their chat session in the middle of a conversation with a neighbour or scary messages from their browser because the connection was closed unexpectedly.
But this feature doesn't cope well with common packaging systems found in Linux distributions or *BSD. However, most of these systems provide some ways to customize several steps of the installation of a package. For instance, Debian, which we use at Yakaz, comes with such a packaging system. We use the maintainer scripts to run whatever is needed to support hot upgrade, even Erlang VM upgrade.
The first section of this article describes briefly how Erlang manages to support hot upgrade (or downgrade), then what is the approach chosen by official Debian packages for Erlang and a common software, Ejabberd. The second section presents how we integrate our Erlang applications in the Debian packaging system to support hot upgrade.
Target audience
This article targets mainly Erlang developers working on Unix platforms. A few notes about what I'll assume or not:
- Knowledge of Erlang is obviously recommended. We don't discuss coding techniques but the article shows some Erlang calls and structures.
- Knowledge of Erlang release handling is not required; the first section will present it.
- I talk about Debian, a Linux distribution, and its packaging system, as describe in the Debian Policy Manual. Knowledge of this system is recommended, though not required: I'll give some details so that people familiar with other packaging system may understand.
No pain, no gain
Erlang release handling
Those already familiar with Erlang release handling may skip to the next subsection.
Erlang application
As we have packages in Perl or Java for instance, we have applications in Erlang. An application brings an homogeneous set of features like a library. It may even be a complete software, like Ejabberd (XMPP server) or Yaws (HTTP server). An application is comprised of:
- a set of Erlang modules
- a file describing the application (the .app file):
- a name
- a version
- a list of applications it depends on
- (optionally) a module to call to start the application's main process
- (optionally) some headers or data files
- (optionally) a file describing how to switch from a version to another (the .appup file)
An application is self-contained in a directory named after application's name and version ($application-$version). This directory is located in the Erlang's lib directory by default. On Debian, this libdir is /usr/lib/erlang/lib. Therefore, the my_app application, version 1.0, would have the following hierarchy:
/usr/lib/erlang
`-- lib
`-- my_app-1.0
`-- ebin
|-- my_app.app # Application's description
|-- my_app_app.beam # Application's modules
|-- my_app_sup.beam
`-- my_app_worker.beam
Erlang release
An Erlang release is:
- a list of applications specifying explicitly each application's version (the .rel file)
- a configuration file containing the configuration directives for all applications (the sys.config file)
- a boot script which contains instructions on how to start those applications (the .script and .boot files)
- (optionally) a script which contains instructions about release upgrade and downgrade (the relup file)
A release is what gets deployed on a production system for instance. A release won't be bootable if an application is missing or if the version expected is missing. It won't boot either if the configuration file is missing.
A release is self-contained in a directory named after its version only (not the name of the service it provides). This directory is located in the Erlang's releases directory, /usr/lib/erlang/releases on Debian. Therefore, the MY_SERVICE 2011.1 release would have the following hierarchy:
/usr/lib/erlang
`-- releases
`-- 2011.1
|-- sys.config # Configuation file
|-- start.rel # Boot script source
|-- start.script # Compiled boot script (text)
|-- start.boot # Compiled boot script (binary)
`-- relup # Release upgrade script
Because the release directory name doesn't contain the service name, unrelated releases could conflict. This is wanted by design: one erlang environment (eg. /usr/lib/erlang on Debian) should not be used to run unrelated releases. The philosophy would be: one environment, one service, several releases of this service. If you need to run several different services, you should make a copy of the environment for each one.
Erlang node
One last concept to understand, the Erlang node. A node is a running instance of the VM. This node executes a release or some random code, like the Erlang shell. A node is designated by a name of the form nodename@hostname. Several nodes, either local or remote, can communicate together.
Release upgrade
A release upgrade consists in switching from a release to another, thus it can be a downgrade too. An upgrade may involve:
- a new list of applications: applications are added, updated or removed
- an updated configuration file
- a new Erlang VM
- a combination of the entries above
To support upgrade, the old or the new release must provide a relup file. This file is either generated from all updated applications' appup files or written by hand. The common case is to generate it but if the upgrade involves a change of VM, this file must be written by hand.
To manage releases, the Erlang executables (found in /usr/lib/erlang/bin on Debian) and the SASL application use two files in the releases directory:
/usr/lib/erlang
`-- releases
|-- RELEASES
`-- start_erl.data
- RELEASES
- This file is used by SASL. It contains a list of the known releases. Each known release specifies a list of application and their absolute path (eg. /usr/.../my_app-1.0), and a state: permanent, old, current, etc. Note that the list of known releases may differ from releases directory's content.
- start_erl.data
- This file contains two fields on a single line: the version of the VM (ERTS' version) and the default release to boot.
When the node is running, we must use the SASL application to do the upgrade. This procedure requires a relup script in either the old or new releases directory and this script must have instructions describing what to do to switch from the old to the new release.
When the node to upgrade is stopped, there's two solution:
- Specify explicitly the new release to boot. Be careful: if the node crashes and heart is configured, the default (old) release will be rebooted.
- Start the node and continue with hot upgrade.
There's no documented recommandation or procedure on how to upgrade incompatible releases or how to upgrade without starting the node. One could modify the RELEASES and start_erl.data files by hand, but it's dangerous because these files are internal to Erlang. We'll discuss in the second section how we handle this case.
During upgrade, SASL's release_handler may:
- stop old applications
- start new applications
- upgrade applications by executing the .appup file's instructions
- give applications a diff of their respective sys.config entry
- restart the node (eg. to upgrade the VM)
This process updates the RELEASES and start_erl.data files accordingly.
With this come two peculiarities:
- Both the old and the new releases must be present simultaneously during the upgrade process. This includes the applications listed in those releases too!
- The procedure is not designed to support changes in the configuration file without creating a new release. The philosophy behind this is that a release is frozen as it was tested before going into production; it should not be modified afterward. There're undocumented ways to reload configuration at runtime though, but we don't discuss them here.
Official Erlang packages
The Erlang environment
The Erlang environment is split into several Debian packages:
- a package called erlang-base which provides ERTS (the VM), the Erlang vanilla release (eg. R14B01), the RELEASES and start_erl.data files, and the core applications: kernel, stdlib, sasl and compiler
- the same package in its Hipe version, called erlang-base-hipe
- one package per application, called erlang-$application
- one meta-package to install the complete environment
Two versions of an Erlang environment are considered as conflicting package: there're two versions of the same package. Therefore, they can't coexist. Moreover, everything is considered as data files, even the RELEASES and start_erl.data files. As a consequence, they're overwritten with each update of the erlang-base or erlang-base-hipe packages, even if only the Debian revision changed, not the Erlang version. Therefore, a third-party package can't reliabily install its own Erlang releases and can't support hot upgrade.
Ejabberd
Ejabberd, an XMPP server, is written as an Erlang application. One can use it as a standalone server or integrate it as a component in a larger system.
Ejabberd's Debian package sees this software only as a standalone server. The files are installed in a non-standard location, /usr/lib/ejabberd, instead of the expected /usr/lib/erlang/lib/ejabberd-$version. Furthermore, it's not deployed as an Erlang release. This approach as several issues:
- A larger system can't use Ejabberd without either adding explicitly the non-standard directory to the search path or by creating a symlink in /usr/lib/erlang/lib.
- The directory doesn't contain the version in its name: two versions can't exist simultaneously.
- An update of the package overwrites the previous version.
Again, a third-party package using Ejabberd or Ejabberd itself can't support hot upgrade.
Erlang-based services
Last but not least, the Erlang meta-package (or the erlang-base package) knows if another package, like Ejabberd, provides a service. And during an update of Erlang, it stops those services, do the update and restarts them, even if they were not running in the first place! Obviously, a stop/start cycle isn't really what could be called a hot upgrade.
Live upgrade with Debian packages
Real-World example
As an example during the following paragraphs, we'll build a complete Erlang environment, called MY_SERVICE:
- Release 2011.1 depends on kernel, stdlib, sasl and mnesia from Erlang R14B01, and my_app1-1.0 and other_app-1.0.
- Release 2011.2 depends on kernel, stdlib, sasl and mnesia from Erlang R14B01, and my_app1-1.1 and my_app2-1.0.
my_app1, my_app2 and other_app are the core applications of the service. This could be Ejabberd or any other already packaged applications. The releases of MY_SERVICE will demonstrate how an application is updated (my_app1 going from version 1.0 to 1.1) and how applications can be added or removed (other_app removed and my_app2 added). An update of the Erlang environment is not covered by this article, but the principle is the same and the presented solution can handle this case.
Pay attention to the name of the Erlang applications and their associated Debian package! Applications use underscores ("_") in their name (and their directory) but Debian packages use dashes ("-"): in a Debian package name, the underscore is used to separate the name of the package from the version.
The final goal is that the administrator just execute this simple command to install the release:
aptitude install my-service
Later, he'll update the system as usual:
aptitude safe-upgrade
Behind the scene, the release must be updated without having to stop the service.
In order to workaround issues without touching the official Erlang Debian package, we must take care of the following things:
- Install a separate Erlang environment to survive an update of the Erlang Debian package.
- If the system uses other Erlang applications, install a copy of the applications in this separate environment, again to survive an update of the related packages.
- During a hot upgrade, add any new applications in the separate environment, likewise for the release files, and call SASL.
I haven't looked yet at the issue with service stop/start during an update of Erlang.
The materials used in this article are available at the following locations:
- my_app1-1.0.tar.gz
- my_app1-1.1.tar.gz
- my_app2-1.0.tar.gz
- other_app-1.0.tar.gz
- MY_SERVICE-2011.1.tar.gz
- MY_SERVICE-2011.2.tar.gz
- erlsvc-1.00.tar.gz
I'll recall the links in the following paragraphs.
Applications my_app1, my_app2 and other_app are the same; only the name and version change. The only exception is a modified .appup file for my_app1-1.1 to handle application upgrade.
I think the solution proposed here can be ported to other packaging systems than Debian's one without much effort if the former provides ways to customize the install/upgrade/remove process.
One package by Erlang application
To ease Erlang applications packaging, we keep one very simple package for each application:
- The application is installed in the standard path: /usr/lib/erlang/lib/$application-$version.
- The package doesn't have any maintainer scripts (scripts used to customize several steps of the installation).
When an application is updated, the previous version is completely removed, so both versions won't coexist in the standard directory. But, because the applications are copied in a separate environment (we'll see how later), this is not a problem.
Here are the applications which we'll use to build the release:
- my_app1-1.0 and other_app-1.0 to build release 2011.1
- my_app1-1.1 and my_app2-1.0 to build release 2011.2
You may wish to look at debian directory of my_app1 for instance. But you won't find anything fancy. The real meat lies in the next paragraph!
For non-Debian users:
A Debian package is built using a bunch of files inside a debian directory, located at the root of the
software sources.
One meta-package to rule them all
All the "magic" resides in a meta-package:
- It depends on Erlang and each required applications, so that they're installed automatically.
- It contains the release files.
- It's responsible for handling the separate environment: initial setup and following upgrades.
- It interacts with the node to call SASL and make the update.
Our example service is called MY_SERVICE and the meta-package my-service. To avoid large maintainer scripts, we use an external control script which exposes high-level operations. This script can then be updated separately. In the examples, we call this script erlsvc.
This time, we have the following hierarchy:
MY_SERVICE-2011.1
|-- Makefile
|-- conf
| |-- .erlang.cookie # Hidden file!
| `-- erlsvc.conf
|-- debian
| |-- changelog
| |-- compat
| |-- control
| |-- copyright
| |-- my-service.config
| |-- my-service.dirs
| |-- my-service.init
| |-- my-service.install.in
| |-- my-service.links.in
| |-- my-service.postinst.in
| |-- my-service.postrm.in
| |-- my-service.preinst.in
| |-- my-service.prerm.in
| |-- my-service.templates
| `-- rules
|-- releases
| |-- 2011.1
| | |-- relup.in
| | `-- sys.config
| |-- R14B01
| | |-- start_clean.rel
| | `-- start_sasl.rel
| `-- start.rel
`-- scripts
|-- changelog2release
|-- control2rel
`-- make-relup
Building the package
The files delivered by this meta-package are the release files only. Applications are delivered by their own package, as stated earlier, and the control script is packaged separately.
The release files are:
- A boot script start.boot. This file is compiled from start.script, a text file containing the low-level instructions. This start.script is generated from start.rel, another text file listing the applications to start and in which order.
- A relup script. This file contains the low-level instructions to handle upgrade and downgrade.
- A sys.config node configuration file. This file contains the configuration parameters for all applications.
If you look at the hierarchy above, you'll see that the sys.config file is there, but the boot script and the relup script are missing. They are generated using the Makefile.
The boot script
We first need to generate a start.rel file. Once we have this file, we can use the standard Erlang tools to build the boot script.
As we said above, the start.rel file lists the applications to start and in which order. Those applications are dependencies of this meta-package, therefore we can find what we need in the debian/control file. Let's take a look at this file.
For non-Debian users:
The debian/control file describes the package: software's
name, maintainer's name, description, packages needed to build it, packages
needed to run it, etc. However, it doesn't specify the version (see debian/changelog) or the commands to build the package
(see debia/rules).
Dependencies listed in debian/control are mainly:
- the erlsvc control script
- the Erlang environment
- Erlang applications
Be careful with this file, because an Erlang release is based on exact version of each application! It must specify an exact version of the packages but not necessarily an exact Debian revision. For instance, MY_SERVICE 2011.1 depends on my_app1 1.0. The packages my-app1_1.0-1 or my-app1_1.0-2 are ok. However, my-app1_1.1-1 isn't! I don't know how to achieve this properly. That's why the control file specifies a range of versions for each application: my_app1's version must be greater or equal to 1.0 but less than 1.1. Here is an excerpt:
Depends: ${misc:Depends}, ucf,
erlsvc (>= 1.0),
erlang-base-hipe (>= 1:14.b.1), erlang-base-hipe (<< 1:14.b.2),
erlang-mnesia (>= 1:14.b.1), erlang-mnesia (<< 1:14.b.2),
my-app1 (>= 1.0), my-app1 (<< 1.1),
other-app (>= 1.0), other-app (<< 1.1)
This way, my_app1's version must be 1.0 but the Debian revision doesn't matter.
The Makefile uses the scripts/control2rel script to generate the start.rel file. This script just extracts the following informations from the debian/control file:
- erlang-base or erlang-base-hipe installs ERTS and the applications kernel, stdlib and sasl among others. The script query the versions of ERTS and those applications and add them to start.rel.
- erlang-mnesia, my-app1 and other-app are other Erlang applications. The script parse the version (eg. ">= 1.0") and add those applications to start.rel.
Here's the start.rel generated from the debian/control above:
{release, {"MY_SERVICE", "2011.1"},
{erts, "5.8.2"},
[
{kernel, "2.14.2"},
{stdlib, "1.17.2"},
{sasl, "2.1.9.2"},
{mnesia, "4.4.16"},
{my_app1, "1.0"},
{other_app, "1.0"}
]
}.
One thing to remember when editing debian/control: the order in which application are listed is important! It determines the start order in start.rel.
At this point, the Makefile can use the following Erlang call to build the boot script:
systools:make_script("releases/2011.1/start", [no_module_tests]).
The relup script
The relup script contains instructions about upgrade/downgrade from other releases. This file isn't required for a release to run, but to upgrade from 2011.1 to 2011.2, we obviously need one in the 2011.2 release package. In fact, we also need one in the 2011.1 release package because we'll treat a first install as an upgrade from eg. R14B01 to 2011.1. Erlang doesn't impose this, we do. This has several advantages:
- only one scenario, no matter if we're doing a first-time install or an upgrade
- same scenario if for instance, 2011.1 could not be hot upgraded to 2011.2: downgrade 2011.1 to R14B01 and upgrade R14B01 to 2011.2
- again, same scenario during package removal: downgrade 2011.1 to R14B01
To generate a relup script, we first need to identify one or more source releases and one target release. The relup.in file is there for that reason: it's an Erlang file containing a list of supported source releases for the release (target release) we're building. To this list, we automatically add the currently installed version of Erlang (eg. R14B01).
That's why, for 2011.1, the relup.in file is empty:
[].
For 2011.2, the relup.in only lists 2011.1:
["2011.1"].
The Makefile calls the scripts/make-relup script to generate the relup file. This script requires:
- the target release's start.rel file. It was generated by the Makefile earlier.
- all the source releases' start.rel files. They were generated by previous run of the Makefile. Therefore, it's important to keep those files once a release is published (eg. by committing them to a repository). At Yakaz for instance, we commit the whole hierarchy and add a new release directory each time we're about to make a new one.
- all applications' versions used by the target release and the sources releases: the relup is built from all the appup scripts. Because Debian packaging allows only one version of a package at a time, we can't use the applications' package and must put the applications elsewhere and use the ERL_LIBS environment variable to point to the directory.
Package creation
Here's how to make the release:
env ERL_LIBS=/path/to/applications make
or, if you're building the Debian package:
env ERL_LIBS=/path/to/applications dpkg-buildpackage ...
Maintainer scripts
Now that we have a shiny packaged release, we must make a few Erlang calls to proceed with its installation or upgrade. We use the package's maintainer scripts for that purpose. If a script fails, the package isn't considered as installed and working and we have a chance to recover from the failure in those scripts too.
However we don't put everything in those scripts to keep them simple and easy to understand. All the code is in the erlsvc external script which exposes high-level commands. Before going through each maitainer script, we'll see what erlsvc can do.
For non-Debian users:
Maintainer scripts are what a packager can use to customize
several steps of the installation/upgrade/removal of a package.
When a script is called and how is well described in the
Debian Policy Manual.
erlsvc
We use a home-brew Perl application to handle our Erlang services (and packages). This application is capable of:
- deploying a separate Erlang environment
- starting/stopping a service (node)
- checking service status
- performing upgrade
- creating a Mnesia schema or joining a cluster (the Erlang distributed database)
- checking a Mnesia cluster consistency
- manage individual applications (start/stop, various queries, change settings)
To do this, the application starts a temporary local Erlang node. This node then talks to the node to manage, using native Erlang communication layer. Thanks to this, we can execute most commands on a local as well as a remote node.
preinst: before the package extraction
This is the simplest maintainer script. Before the meta-package gets installed or upgraded, we do nothing!
postinst: after the package extraction
This script has a lot of work to do.
- Declare configuration files using ucf(1). In our example, there's only one file: sys.config.
- Create a user account because we don't want the service to be executed as root. Just after the account creation, we fix some permissions.
- (erlsvc) Deploy the separate Erlang environment in the dedicated user's home directory:
- Use rsync(1) to create or upgrade the separate environment from the central one (in /usr/lib/erlang).
- Update the Erlang root directory in scripts such as bin/erl.
- Update the releases directory with potential new Erlang vanilla releases.
- (erlsvc) Setup Mnesia: create a schema for the first node or join an existing cluster for other nodes. The package uses debconf to ask the user what to do.
- (erlsvc) Proceed with upgrade from current release (or Erlang vanilla release, eg. R14B01):
- Check if the node is running and if it can be upgraded from the source release to the target release.
- If it is running and can be upgraded: proceed with upgrade.
- If it's not:
- If the node is running, stop it.
- Downgrade to Erlang vanilla release.
- Upgrade to target release.
- If the node was running before upgrade, restart it.
If you plan to join a Mnesia cluster, be sure that the node you specify is running and reachable, otherwise the node won't be able to join.
There's a caveat with hot upgrade when the node is not running: Erlang will boot the target release, therefore the service will be up for a short period of time. One solution would be to manually activate the service after the node is running (eg. from an init script or a modified erlsvc). For instance, your service starts a web server but you don't want to serve requests from this node right now. You could mark the web server application as "load only" in your start.rel and start it manually whenever you want. However, the node will synchronize with the Mnesia cluster. Be careful if you depend on Mnesia events.
prerm: before the package removal
This script is another important step.
- (erlsvc) Check that the service is stopped (or refuse to remove the package).
- (erlsvc) Leave Mnesia cluster and destroy the schema.
- (erlsvc) Delete the separate environment.
This script is merely the postinst script reversed.
As with postinst, if the node must leave a Mnesia cluster, at least one of the other cluster members must be running and reachable!
postrm: after the package removal
This script only needs to do two simple things:
- Remove the dedicated user account.
- Unregister configuration files using ucf(1).
Practicing
Now that you understand how to build the needed packages and how they relate, let's take the example release MY_SERVICE 2011.1, build and install it, then upgrade it to 2011.2.
Before we start, you may need to install the following Debian packages:
- erlang-base-hipe
- erlang-eunit
- erlang-tools
- erlang-dev
- erlang-dialyzer
- debhelper
- fakeroot
- autotools-dev
Building and installing 2011.1
- We start with the erlsvc control
script:
dpkg-buildpackage -rfakeroot -uc -us -b -tc - Now the packages for my_app1-1.0 and
other_app-1.0. Because we'll need them later
installed without the Debian package, we first build the application as usual:
./configure --prefix=${HOME}/MY_SERVICE-apps make make install make distclean - Then, we can build the applications' Debian package:
dpkg-buildpackage -rfakeroot -uc -us -b -tcOf course, if build time is long, you may want to only build the package and either extract the files or install the package and copy the files to ${HOME}/MY_SERVICE-apps. - We must install the application packages we just built: they're
bulid-time dependencies of MY_SERVICE 2011.1:
dpkg -i ./my-app1_1.0-1_all.deb ./other-app_1.0-1_all.deb - To build MY_SERVICE's package, we
point to the directory where we installed the applications (though, it's
not required for 2011.1 because this is the first release):
env ERL_LIBS=${HOME}/MY_SERVICE-apps \ dpkg-buildpackage -rfakeroot -uc -us -b -tc
At this point, the packages for MY_SERVICE 2011.1 are ready:
erlsvc_1.00-1_all.deb
erlsvc_1.00-1_amd64.changes
my-app1_1.0-1_all.deb
my-app1_1.0-1_amd64.changes
my-service_2011.1-1_all.deb
my-service_2011.1-1_amd64.changes
other-app_1.0-1_all.deb
other-app_1.0-1_amd64.changes
You can push them to your Debian repository and use apt-get(1)/aptitude(1)/whatever, but for this article, I install them directly. Therefore, automatic dependencies installation won't work and I install them manually:
dpkg -i ./erlsvc_1.00-1_all.deb ./my-app1_1.0-1_all.deb \
./other-app_1.0-1_all.deb ./my-service_2011.1-1_all.deb
The service is ready to start!
erlsvc start
Starting My service (2011.1): done.
We may check the current release of "MY_SERVICE":
erlsvc release current
2011.1
Upgrading to 2011.2
In the following steps, I only indicate the most important updates, but not the common updates to files such as the debian/changelog.
- Applications have changed for 2011.2: we build
my_app-1.1 and my_app2-1.0. Because my_app1-1.1 is an update
to my_app1-1.0, the
.appup file (my_app1-1.1/ebin/my_app1.appup.in) tells
what to do during upgrade/downgrade: here, we reload module my_app1:
{ "@VERSION@", [ %% To upgrade from the specified version to current one. {"1.0", [{load_module, my_app1}]} ], [ %% To downgrade from the current version to the specified one. {"1.0", [{load_module, my_app1}]} ] }. - To build the application packages, nothing has changed: proceed like step #2 and #3 above.
- We must install the new application packges because they're
build-time dependencies of MY_SERVICE
2011.2:
dpkg -i ./my-app1_1.1-1_all.deb ./my-app2_1.0-1_all.deb - In MY_SERVICE, we
keep the directory for 2011.1 containing the generated
start.rel (other generated
files can be thrown away). We add a directory for 2011.2
containing sys.config and
relup.in. In the relup.in file, we tell that 2011.2 supports
upgrade from 2011.1:
["2011.1"]. - We must update the debian/control
file to indicates the new applications/new versions:
Depends: ${misc:Depends}, ucf, erlsvc (>= 1.0), erlang-base-hipe (>= 1:14.b.1), erlang-base-hipe (<< 1:14.b.2), erlang-mnesia (>= 1:14.b.1), erlang-mnesia (<< 1:14.b.2), my-app1 (>= 1.1), my-app1 (<< 1.2), # upgrade from 1.0 to 1.1 my-app2 (>= 1.0), my-app2 (<< 1.1) # my_app2 replaces other_app - To build the package, we use the same command as for 2011.1:
env ERL_LIBS=${HOME}/MY_SERVICE-apps dpkg-buildpackage -rfakeroot -uc -us -b -tc
The new packages to push to the repository are:
my-app1_1.1-1_all.deb
my-app1_1.1-1_amd64.changes
my-app2_1.0-1_all.deb
my-app2_1.0-1_amd64.changes
my-service_2011.2-1_all.deb
my-service_2011.2-1_amd64.changes
Let's do the upgrade:
dpkg -i ./my-app1_1.1-1_all.deb ./my-app2_1.0-1_all.deb \
./my-service_2011.2-1_all.deb
...
Service upgraded from release '2011.1' to '2011.2'
We may check the current release of MY_SERVICE again:
erlsvc release current
2011.2
"I love it when a plan comes together!" -- Hannibal
Upgrading Erlang
To conclude, let's talk briefly about an upgrade of Erlang itself.
If a release updates the Erlang VM, the procedure is the same. Just update your debian/control accordingly and be sure to have an empty relup.in file. erlsvc does the following steps:
- stop the service
- update the separate environment; it'll then have both Erlang versions
- downgrade to a vanilla release
- upgrade to the new release
- start the service
If you update the Erlang Debian packages (same Erlang version, new Debian revision), no matter if you're upgrading your release or not, it will stop your service before upgrade and restart it afterward. I haven't look at this problem yet.
Both situations may be covered by another article! Meanwhile, I'm interested in your experience with Erlang applications deployment, no matter the platform.
Jean-Sébastien PédronYakaz engineer
2011/03/21
Comments