Partial preview of the text
Download UNIX and Linux System Administration and more Schemes and Mind Maps Linux skills in PDF only on Docsity!
Creating reproducible environments Programs, libraries, and languages develop complex webs of dependencies as they evolve together over time. A production-level server might depend on tens or hundreds of these components, each of which has its own expectations about the installation environment. How do you identify which combination of library versions will create a harmonious environment? How do you make sure the configuration you tested in the development lab is the same one that gets deployed to the cloud? More basically, how do you make sure that managing all these parts isn’t a big hassle? Both Python and Ruby have a standardized way for packages to express their dependencies. In both systems, package developers create a text file at the root of the project that lists its dependencies. For Ruby, the file is called Gemfile, and for Python, requirements.txt. Both formats support flexible version specifications for dependencies, so it’s possible for packages to declare that they’re compatible with “any release of simplejson version 3 or higher” or “Rails 3, but not Rails 4.” It’s also possible to specify an exact version requirement for any dependency. Both file formats allow a source to be specified for each package, so dependencies need not be distributed through the language’s standard package warehouse. All common sources are supported, from web URLs to local files to GitHub repositories. You install a batch of Python dependencies with pip install -r requirements.txt. Although pip does a fine job of resolving individual version specifications, it’s unfortunately not able to solve complex dependency relationships among packages on its own. Developers sometimes have to tweak the order in which packages are mentioned in the requirements.txt file to achieve a satisfactory result. It’s also possible, though uncommon, for new package releases to disturb the version equilibrium. pip freeze prints out Python’s current package inventory in requirements.txt format, specifying an exact version for each package. This feature can be helpful for replicating the current environment on a production server. In the Ruby world, gem install -g Gemfile is a fairly direct analog of pip -r. In most circumstances, though, it’s better to use the Bundler gem to manage dependencies. Run gem install bundler to install it (if it’s not already on the system), then run bundle install from the root directory of the project you’re setting up. (Ruby gems can include shell-level commands. They don’t typically have man pages, though; run bundle help for details, or see bundler.io for complete documentation.) Bundler has several nice tricks up its sleeve: ¢ It does true recursive dependency management, so if there’s a set of gems that are mutually compatible and that satisfy all constraints, Bundler can find it without help.