Added volume support, forced running nix-docker as root when building stand-alone images

This commit is contained in:
Zef Hemel 2013-11-04 08:32:40 -08:00
parent 20c4115a21
commit a5e01e7c18
6 changed files with 93 additions and 34 deletions

View File

@ -1,7 +1,7 @@
{ config, pkgs, ... }:
{
docker.ports = [ 1234 80 ];
docker.verbose = true;
docker.ports = [ 1234 80 22 ];
docker.volumes = [ "/data" ];
services.redis = {
enable = true;

View File

@ -11,10 +11,10 @@ var execFile = require('child_process').execFile;
var configFile = argv.c || "configuration.nix";
var fullBuild = !!argv.b;
var baseImage = argv.from = "zefhemel/base-nix";
var imageName = argv.t ? argv.t : "nix-docker-build";
var baseImage = argv.from || "zefhemel/base-nix";
var imageName = argv.t || "nix-docker-build";
var tmpNixStore = "nix_store";
var nixClosureCopy = "nix-closure";
if (argv.help) {
console.log("Usage: nix-docker [-b] [-t imagename] [-c configuration.nix] ");
@ -36,7 +36,7 @@ function pipeRun(cmd, args, callback) {
}
function build(nix, configPath, callback) {
var nixBuild = spawn('nix-build', [nix, '-I', 'configuration=' + configPath, "--arg", "mountBuild", "" + !fullBuild, "--argstr", "name", imageName, "--argstr", "baseImage", baseImage, "--show-trace"]);
var nixBuild = spawn('nix-build', [nix, '-I', 'configuration=' + configPath, "--arg", "mountBuild", "" + !fullBuild, "--argstr", "name", imageName, "--argstr", "baseImage", baseImage, "--show-trace"].concat(fullBuild ? ["--no-out-link"] : []));
var nixPath;
nixBuild.stdout.on('data', function(data) {
@ -57,28 +57,24 @@ function cleanup(callback) {
if(!fullBuild) {
return callback();
}
if (!fs.existsSync(tmpNixStore)) {
if (!fs.existsSync(nixClosureCopy)) {
return callback();
}
execFile("chmod", ["-R", "777", tmpNixStore], function() {
execFile("rm", ["-rf", tmpNixStore], callback);
});
pipeRun("rm", ["-rf", nixClosureCopy], callback);
}
function buildImage(dockerFilePath, callback) {
var dockerFile = fs.readFileSync(dockerFilePath + "/Dockerfile").toString("ascii");
fs.writeFileSync("Dockerfile", dockerFile);
if (!argv["dockerfile-only"]) {
pipeRun("sudo", ["docker", "build", "-rm=true", "-t", imageName, "."], function(code) {
cleanup(function() {
callback(code);
});
pipeRun("docker", ["build", "-rm=true", "-t", imageName, "."], function(code) {
cleanup(function() {
callback(code);
});
}
});
}
function getAvailableNixPaths(callback) {
var command = spawn("sudo", ["docker", "run", baseImage, "/bin/ls", "/nix/store"]);
var command = spawn("docker", ["run", baseImage, "/bin/ls", "/nix/store"]);
process.stdin.pipe(command.stdin);
var output = '';
@ -106,15 +102,17 @@ function copyClosureAndBuild(dockerFilePath, availablePaths) {
console.log("New paths to copy", paths);
fs.mkdirSync(tmpNixStore);
execFile("cp", ["-r", "--no-preserve=ownership"].concat(paths).concat([tmpNixStore]), function(err) {
if (err) {
console.log(err);
process.exit(1);
}
buildImage(dockerFilePath, function(code) {
console.log("To run: sudo docker run -t -i " + imageName);
process.exit(code);
fs.mkdirSync(nixClosureCopy);
execFile("cp", ["-r"].concat(paths).concat([nixClosureCopy]), function(err) {
pipeRun("chown", ["-R", "root:root", nixClosureCopy], function() {
if (err) {
console.log(err);
process.exit(1);
}
buildImage(dockerFilePath, function(code) {
console.log("To run: sudo docker run -t -i " + imageName);
process.exit(code);
});
});
});
} else {
@ -126,8 +124,12 @@ function copyClosureAndBuild(dockerFilePath, availablePaths) {
});
}
if(fullBuild && process.env.USER !== "root") {
console.error("When doing a full build you need to run nix-docker as root. Rerun this command with 'sudo -E nix-docker ...'");
process.exit(1);
}
cleanup(function() {
build(rootPath + "/dockerfile.nix", configFile, function(code, dockerFilePath) {
build(rootPath + "/docker.nix", configFile, function(code, dockerFilePath) {
if(code) {
process.exit(code);
}

View File

@ -2,7 +2,7 @@
, name
, configuration ? <configuration>
, mountBuild ? true
, baseImage ? "ubuntu"
, baseImage ? "busybox"
}:
with pkgs.lib;
let
@ -34,7 +34,7 @@ let
FROM ${if mountBuild then "busybox" else baseImage}
${if !mountBuild then
''
ADD nix_store /nix/store
ADD nix-closure /nix/store
RUN ${buildScript}
''
else ""}
@ -42,6 +42,9 @@ let
${
concatMapStrings (port: "EXPOSE ${toString port}\n") config.config.docker.ports
}
${
concatMapStrings (port: "VOLUME ${toString port}\n") config.config.docker.volumes
}
'';
imageHash = substring 11 8 dockerFile.outPath;

View File

@ -8,6 +8,12 @@ with pkgs.lib;
example = [ 80 22 ];
};
docker.volumes = mkOption {
default = [];
description = "Volumes to create for container.";
example = [ "/var/lib" "/var/log" ];
};
docker.buildScripts = mkOption {
default = {};
example = {
@ -28,16 +34,13 @@ with pkgs.lib;
type = types.bool;
};
# HACK: Let's ignore these for now
networking = mkOption {};
security = mkOption {};
#system.nssModules.path = mkOption {};
#services.samba = mkOption{};
};
config = {
docker.buildScript = concatStrings (attrValues config.docker.buildScripts);
networking.enableIPv6 = false;
#system.nssModules.path = "";
#services.samba.syncPasswordsByPam = false;
};
}

View File

@ -35,7 +35,7 @@ in {
rm -rf /usr
chmod 777 /tmp
ln -s ${systemEnv} /usr
ln -s /usr/bin/bash /bin/bash
ln -sf /usr/bin/bash /bin/bash
'';
environment.systemPackages = with pkgs; [ coreutils bash ];

View File

@ -0,0 +1,51 @@
{ pkgs, config, ... }:
with pkgs.lib;
let
services = config.systemd.services;
isOneShot = cfg: hasAttr "Type" cfg.serviceConfig && cfg.serviceConfig.Type == "oneshot";
runServices = filterAttrs (name: cfg: !(isOneShot cfg)) services;
oneShotServices = filterAttrs (name: cfg: isOneShot cfg) services;
configToCommand = name: cfg: ''
#!/bin/sh -e
${if hasAttr "preStart" cfg then cfg.preStart else ""}
${if hasAttr "ExecStart" cfg.serviceConfig then
cfg.serviceConfig.ExecStart
else if hasAttr "script" cfg then
cfg.script
else
""
}
${if hasAttr "postStart" cfg then cfg.postStart else ""}
'';
in {
options = {
systemd.services = mkOption { }; # TODO make more specific
};
config = {
docker.buildScripts."1-systemd-oneshot" = concatMapStrings (name: "${configToCommand name (getAttr name oneShotServices)}\n") (attrNames oneShotServices);
supervisord.services = listToAttrs (map (name:
let
cfg = getAttr name runServices;
in
{
name = name;
value = {
command = pkgs.writeScript "${name}-run" (configToCommand name cfg);
user = if hasAttr "User" cfg.serviceConfig then cfg.serviceConfig.User else "root";
environment = (if hasAttr "environment" cfg then cfg.environment else {}) //
(if hasAttr "path" cfg then
{ PATH = concatStringsSep ":" (map (prg: "${prg}/bin") cfg.path); }
else {});
};
}
) (attrNames runServices));
};
}