This commit is contained in:
Zef Hemel 2013-10-31 10:15:19 -07:00
parent 39ba325315
commit 509835211f
9 changed files with 244 additions and 107 deletions

4
configuration.nix Normal file
View File

@ -0,0 +1,4 @@
{ config, pkgs, ... }:
{
services.redis.enable = true;
}

View File

@ -9,8 +9,8 @@ let
});
in
nodePackages.buildNodePackage {
name = "nixdocker";
src = [ { outPath = ./src; name = "nixdocker"; } ];
name = "nix-docker";
src = [ { outPath = ./src; name = "nix-docker"; } ];
deps = with nodePackages; [optimist];
passthru.names = [ "nixdocker" ];
passthru.names = [ "nix-docker" ];
}

6
src/base.nix Normal file
View File

@ -0,0 +1,6 @@
{ config, pkgs, ... }:
{
config = {
fileSystems."/".device = "/dev/disk/by-label/nixos";
};
}

126
src/bin/nix-docker Normal file
View File

@ -0,0 +1,126 @@
#!/usr/bin/env node
var argv = require("optimist").argv;
var fs = require("fs");
var path = require("path");
var rootPath = path.resolve(fs.realpathSync(process.argv[1]), "../..");
var spawn = require('child_process').spawn;
var execFile = require('child_process').execFile;
var configFile = argv.c || "configuration.nix";
var imageName = argv.t ? argv.t : "nix-docker-build";
var tmpNixStore = "nix_store";
if(argv.help) {
console.log("Usage: nix-docker [--dockerfile-only] [--mount-build] [-t imagename] [-c configuration.nix] ");
console.log(" --docker-file-only: generate Docker file, but do not build it.");
console.log(" --mount-build: don't add /nix paths to container, but let them be mounted from host at run-time with -v.");
console.log(" -t: name of the image to build.");
console.log(" -c: path to configuration file to build.");
process.exit(0);
}
function pipeRun(cmd, args, callback) {
var command = spawn(cmd, args);
command.stdout.pipe(process.stdout);
command.stderr.pipe(process.stderr);
command.on('close', function(code) {
callback(code);
});
}
function build(nix, configPath, callback) {
var nixBuild = spawn('nix-build', [nix, '-I', 'configuration=' + configPath]);
var nixPath;
nixBuild.stdout.on('data', function(data) {
nixPath = data.toString("ascii");
});
nixBuild.stderr.pipe(process.stderr);
nixBuild.on('close', function(code) {
if (code === 0) {
callback(null, nixPath.trim());
} else {
callback(code);
}
});
}
function cleanup(callback) {
if(!fs.existsSync(tmpNixStore)) {
return callback();
}
var stats = fs.lstatSync(tmpNixStore);
if(stats.isSymbolicLink()) {
fs.unlinkSync(tmpNixStore);
callback();
} else {
execFile("chmod", ["-R", "777", tmpNixStore], function() {
execFile("rm", ["-rf", tmpNixStore], callback);
});
}
}
function buildImage(dockerFilePath, dockerLines, callback) {
var dockerFile = fs.readFileSync(dockerFilePath + "/Dockerfile").toString("ascii");
fs.writeFileSync("Dockerfile", dockerFile.replace("<<BODY>>", dockerLines.join("\n")));
if(!argv["dockerfile-only"]) {
pipeRun("docker", ["build", "-t", imageName, "."], function(code) {
cleanup(function() {
callback(code);
});
});
}
}
cleanup(function() {
build(rootPath + "/dockerfile.nix", configFile, function(err, dockerFilePath) {
execFile("nix-store", ["-qR", dockerFilePath], {}, function(err, stdout) {
if (err) {
return console.error(err);
}
var paths = stdout.trim().split("\n");
var dockerLines = [];
if(argv["big-commit"]) {
fs.mkdirSync(tmpNixStore);
execFile("cp", ["-r", "--no-preserve=ownership"].concat(paths).concat([tmpNixStore]), function(err, stdout, stderr) {
if(err) {
console.log(err);
process.exit(1);
}
console.log(stdout, stderr);
dockerLines.push("ADD " + tmpNixStore + " /nix/store");
console.log("Docker lines", dockerLines);
buildImage(dockerFilePath, dockerLines, function(code) {
console.log("To run: docker run -t -i " + imageName);
process.exit(code);
});
});
} else if(argv["mount-build"]) {
buildImage(dockerFilePath, dockerLines, function(code) {
console.log("To run: docker run -t -i -v /nix/store:/nix/store " + imageName);
process.exit(code);
});
} else {
fs.symlinkSync("/nix/store", tmpNixStore);
paths.forEach(function(path) {
dockerLines.push("ADD " + tmpNixStore + path.substring("/nix/store".length) + " " + path);
});
buildImage(dockerFilePath, dockerLines, function(code) {
console.log("To run: docker run -t -i " + imageName);
process.exit(code);
});
}
});
});
});

View File

@ -1,69 +0,0 @@
#!/usr/bin/env node
var optimist = require("optimist");
var fs = require("fs");
var path = require("path");
var rootPath = path.resolve(fs.realpathSync(process.argv[1]), "../..");
console.log("Root path", rootPath);
var spawn = require('child_process').spawn;
var execFile = require('child_process').execFile;
function pipeRun(cmd, args, callback) {
var command = spawn(cmd, args);
command.stdout.pipe(process.stdout);
command.stderr.pipe(process.stderr);
command.on('close', function(code) {
callback(code);
});
}
function build(nix, configPath, callback) {
var nixBuild = spawn('nix-build', [nix, '-I', 'configuration=' + configPath]);
var nixPath;
nixBuild.stdout.on('data', function(data) {
nixPath = data.toString("ascii");
});
nixBuild.stderr.pipe(process.stderr);
nixBuild.on('close', function(code) {
if (code === 0) {
callback(null, nixPath.trim());
} else {
callback(code);
}
});
}
build(rootPath + "/docker.nix", "configuration.nix", function(err, startPath) {
build(rootPath + "/dockerfile.nix", "configuration.nix", function(err, dockerFilePath) {
execFile("nix-store", ["-qR", startPath], {}, function(err, stdout) {
if (err) {
return console.error(err);
}
var paths = stdout.split("\n");
var dockerFile = fs.readFileSync(dockerFilePath + "/Dockerfile").toString("ascii");
var dockerLines = [];
if(!fs.existsSync("nix_symlink")) {
fs.symlinkSync("/nix", "nix_symlink");
}
paths.forEach(function(path) {
if (path) {
dockerLines.push("ADD " + "nix_symlink" + path.substring("/nix".length) + " " + path);
}
});
dockerLines.push("CMD " + startPath + "/bin/start");
fs.writeFileSync("Dockerfile", dockerFile.replace("<<BODY>>", dockerLines.join("\n")));
pipeRun("docker", ["build", "-t", "test", "."], function(code) {
fs.unlinkSync("nix_symlink");
process.exit(code);
});
});
});
});

View File

@ -3,25 +3,7 @@
}:
let
inherit (pkgs.lib) concatMapStrings getAttr attrNames hasAttr;
stdenv = pkgs.stdenv;
supervisorConfig = pkgs.writeText "supervisord.conf" ''
[supervisord]
logfile=/tmp/supervisord.log
${concatMapStrings (name:
let
cfg = getAttr name configuration.services;
in
''
[program:${name}]
command=${cfg.command}
${if hasAttr "cwd" cfg then
"directory=${cfg.cwd}"
else ""}
''
) (attrNames configuration.services)
}
'';
startScript = pkgs.writeText "start" ''
${pkgs.pythonPackages.supervisor}/bin/supervisord -c ${supervisorConfig} -n
'';

View File

@ -1,26 +1,102 @@
{ pkgs ? import <nixpkgs> {}
, configuration ? import <configuration> { inherit pkgs; }
, configuration ? <configuration>
}:
with pkgs.lib;
let
inherit (pkgs.lib) hasAttr concatMapStrings;
config = import <nixpkgs/nixos/lib/eval-config.nix> {
modules = [ configuration ./base.nix ];
};
services = removeAttrs config.config.systemd.services [
"acpid"
"network-setup"
"prepare-kexec"
"systemd-sysctl"
"alsa-store"
"nix-daemon"
"rngd"
"systemd-update-utmp"
"cpufreq"
"nix-gc"
"scsi-link-pm"
"systemd-vconsole-setup"
"cron"
"nscd"
"synergy-client"
"update-locatedb"
"dhcpcd"
"ntpd"
"synergy-server"
"post-resume"
"systemd-modules-load"
"klogd"
"pre-sleep"
"systemd-random-seed"
];
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 = cfg: if hasAttr "ExecStart" cfg.serviceConfig then
cfg.serviceConfig.ExecStart
else if hasAttr "script" cfg then
pkgs.writeScript "script" ''
#!/bin/sh
${cfg.script}
''
else
"";
supervisorConfig = pkgs.writeText "supervisord.conf" ''
[supervisord]
logfile=/tmp/supervisord.log
${concatMapStrings (name:
let
cfg = getAttr name runServices;
in
''
[program:${name}]
command=${configToCommand cfg}''
) (attrNames runServices)
}
'';
extraUsers = config.config.users.extraUsers;
dockerFile = pkgs.writeText "Dockerfile" ''
FROM busybox
FROM ubuntu
<<BODY>>
# Create users
${
if hasAttr "docker" configuration && hasAttr "ports" configuration.docker then
concatMapStrings (port: "EXPOSE ${toString port}\n") configuration.docker.ports
else
concatMapStrings (name: "RUN /usr/sbin/useradd ${name} || echo\n") (attrNames extraUsers)
}
# Run one shot services
${
concatMapStrings (name: "RUN ${configToCommand (getAttr name oneShotServices)}\n") (attrNames oneShotServices)
}
${
# if hasAttr "docker" configuration && hasAttr "ports" configuration.docker then
# concatMapStrings (port: "EXPOSE ${toString port}\n") configuration.docker.ports
# else
# ""
""
}
CMD ${pkgs.pythonPackages.supervisor}/bin/supervisord -c ${supervisorConfig} -n
'';
in pkgs.stdenv.mkDerivation {
name = "dockerfile";
src = ./.;
phases = [ "installPhase" ];
installPhase = ''
mkdir -p $out
cp ${dockerFile} $out/Dockerfile
'';
name = "dockerfile";
src = ./.;
phases = [ "installPhase" ];
installPhase = ''
mkdir -p $out
cp ${dockerFile} $out/Dockerfile
'';
}

View File

@ -1,5 +1,5 @@
{
"name" : "nixdocker",
"name" : "nix-docker",
"version" : "0.1.0",
"dependencies" : {
"optimist" : "0.6.0"

12
zedconfig.json Normal file
View File

@ -0,0 +1,12 @@
{
"modes": {
"javascript": {
"filenames": ["nix-docker"]
},
"nix": {
"preferences": {
"tabSize": 2
}
}
}
}