├── .gitignore ├── .gitmodules ├── DropdockRoboFile.php ├── README.md ├── Robofile.php ├── composer.json ├── docker-compose.yml.dist ├── dropdock └── php-src └── DropdockRunner.php /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | dropdock.phar 3 | /data 4 | docker-compose.yml 5 | docker-compose.yml.dev 6 | src/github-repos 7 | vendor 8 | composer.lock 9 | tmp 10 | .vagrant 11 | Vagrantfile 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src"] 2 | path = src 3 | url = git@github.com:twinbit/dropdock-containers.git 4 | -------------------------------------------------------------------------------- /DropdockRoboFile.php: -------------------------------------------------------------------------------- 1 | yell("Dropdock init."); 30 | $base_path = $this->getBasePath(); 31 | 32 | // Create directory structure. 33 | $this->taskFileSystemStack() 34 | ->mkdir('data') 35 | ->mkdir('bin') 36 | ->run(); 37 | 38 | // Create static binaries. 39 | $this->createBinaries(); 40 | 41 | // Make binaries executables. 42 | $this->taskExec('chmod -R +x bin')->run(); 43 | 44 | // Rename fig.yml.dist to docker-compose.yml 45 | $this->taskFileSystemStack() 46 | ->copy($base_path . '/docker-compose.yml.dist', 'docker-compose.yml') 47 | ->run(); 48 | $uid = trim($this->taskExec('id -u')->run()->getMessage()); 49 | $gid = trim($this->taskExec('id -g')->run()->getMessage()); 50 | $this->taskReplaceInFile('docker-compose.yml') 51 | ->from('##LOCAL_UID##') 52 | ->to($uid) 53 | ->run(); 54 | $this->taskReplaceInFile('docker-compose.yml') 55 | ->from('##LOCAL_GID##') 56 | ->to($gid) 57 | ->run(); 58 | } 59 | 60 | /** 61 | * Recreate containers binaries. 62 | */ 63 | public function createBinaries() 64 | { 65 | $yaml = new Parser(); 66 | $base_path = $this->getBasePath(); 67 | $cwd = getcwd(); 68 | $files = Finder::create()->ignoreVCS(true) 69 | ->files() 70 | ->name('binaries.yml') 71 | ->in(__DIR__); 72 | foreach ($files as $file) { 73 | $binaries = $yaml->parse(file_get_contents($base_path . '/' . $file->getRelativePathname())); 74 | foreach ($binaries as $container => $binaries) { 75 | foreach ($binaries as $bin => $opts) { 76 | $this->taskWriteToFile("bin/{$bin}") 77 | ->line(isset($opts['env']) ? $opts['env'] : '#!/usr/bin/env bash') 78 | ->line("cd {$cwd} && docker-compose run --rm {$container} {$opts['bin']} {$opts['arguments']}") 79 | ->run(); 80 | } 81 | } 82 | } 83 | } 84 | 85 | /** 86 | * Symlink www and bin folders. 87 | */ 88 | public function symlink() 89 | { 90 | $this->taskFileSystemStack() 91 | ->symlink('data/var/www', 'www') 92 | ->run(); 93 | } 94 | 95 | /** 96 | * Reconfigure boot2docker cpu/memory. 97 | */ 98 | public function boot2dockerOptimize($opts = ['cpu' => '1', 'memory' => '8192']) 99 | { 100 | $memory = $opts['memory']; 101 | $cpu = $opts['cpu']; 102 | $this->taskExecStack() 103 | ->stopOnFail(TRUE) 104 | ->exec('boot2docker stop') 105 | ->exec('VBoxManage modifyvm "boot2docker-vm" --memory ' . $memory . ' --cpus ' . $cpu) 106 | ->exec('boot2docker up') 107 | ->run(); 108 | } 109 | 110 | /** 111 | * Configure NFS mount boot script. 112 | * 113 | * @todo this task needs to be explained better (fe: howto configure nfs exports locally). 114 | */ 115 | public function boot2dockerNfsSetup() 116 | { 117 | $base_path = $this->getBasePath(); 118 | $mount_boot_script = file_get_contents($base_path . '/src/scripts/boot2local.sh'); 119 | $this->taskExecStack() 120 | ->stopOnFail(FALSE) 121 | ->exec('boot2docker ssh "sudo rm -f /var/lib/boot2docker/bootlocal.sh && sudo touch /var/lib/boot2docker/bootlocal.sh"') 122 | ->exec('boot2docker ssh "echo \'' . $mount_boot_script . '\' | sudo tee -a /var/lib/boot2docker/bootlocal.sh" >/dev/null') 123 | ->exec('boot2docker ssh "sudo chmod +x /var/lib/boot2docker/bootlocal.sh" > /dev/null') 124 | ->exec('boot2docker restart') 125 | ->run(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dropdock 2 | 3 | ## Installing 4 | 5 | ### Phar 6 | 7 | [Download dropdock.phar >](http://twinbit.github.io/dropdock/dropdock.phar) 8 | 9 | ``` 10 | wget http://twinbit.github.io/dropdock/dropdock.phar 11 | ``` 12 | 13 | To install globally put `dropdock.phar` in `/usr/bin`. 14 | 15 | ``` 16 | sudo chmod +x dropdock.phar && sudo mv dropdock.phar /usr/bin/dropdock 17 | ``` 18 | 19 | Now you can use it just like `dropdock`. 20 | 21 | ## Usage 22 | 23 | Just run `dropdock init` in a empty folder to bootstrap a new dropdock project: 24 | 25 | ``` 26 | |-- bin 27 | | |-- cli 28 | | |-- drush 29 | | |-- mysql 30 | | |-- mysql_cli 31 | | |-- mysql_create 32 | | |-- mysql_import 33 | | |-- phing 34 | | `-- phpcs 35 | |-- data 36 | `-- fig.yml 37 | ``` 38 | 39 | (@TODO) Tweak `fig.yml` to match your needs and run `fig up -d` to run the containers. 40 | At the first run fig will download and build remote containers, it can takes several minutes. 41 | 42 | 43 | ## Boot2docker configuration steps: 44 | 45 | In order to not going insane trying to fix vboxfs shared folder permissions, it is better to 46 | use NFS from OSX in order to have an automatic mapping to local user uid/gid: 47 | 48 | ### OSX NFS Export 49 | 50 | Edit your /etc/exports file as follows: 51 | 52 | ``` 53 | /Users -mapall=youruser:staff boot2docker 54 | ``` 55 | 56 | ### Booot2docker configuration 57 | 58 | ``` 59 | boot2docker ssh 60 | sudo umount /Users 61 | sudo /usr/local/etc/init.d/nfs-client start 62 | # See http://www.slashroot.in/how-do-linux-nfs-performance-tuning-and-optimization 63 | # See http://www.gossamer-threads.com/lists/wiki/mediawiki-cvs/500057 64 | sudo mount 192.168.59.3:/Users /Users -o rw,async,noatime,rsize=32768,wsize=32768,proto=tcp 65 | ``` 66 | 67 | ## Sublime text NFS bug 68 | 69 | If you are using SublimeText, you could experience this problem: https://github.com/mitchellh/vagrant/issues/2768: 70 | `NFS not updating files if the file length stayed the same.` 71 | 72 | To fix it: Sublime Text > Preferences > Settings- User 73 | 74 | ``` 75 | { 76 | "atomic_save": false 77 | } 78 | ``` 79 | 80 | ## TODO 81 | 82 | - Move boot2local nfs configurations out of https://github.com/twinbit/dropdock-containers repository 83 | - Refactor dropdockRoboFile::boot2dockerNfsSetup() to handle better mount.nfs "fsc" options (Related to cachefilesd) 84 | - Create a custom iso tu automatically run the cachefilesd repository 85 | 86 | ``` 87 | FROM ubuntu:14.04 88 | MAINTAINER Paolo Mainardi "paolo@twinbit.it" 89 | ENV UPDATE_AT 1 90 | RUN apt-get update && apt-get -y install cachefilesd 91 | CMD /sbin/cachefilesd -n -f /etc/cachefilesd.conf -s 92 | ``` 93 | -------------------------------------------------------------------------------- /Robofile.php: -------------------------------------------------------------------------------- 1 | yell("Releasing Dropdock"); 15 | $this->taskExecStack() 16 | ->stopOnFail() 17 | ->exec("git submodule update --init --recursive --remote") 18 | ->run(); 19 | $this->taskGitStack() 20 | ->add('-A') 21 | ->commit("auto-update") 22 | ->pull() 23 | ->push() 24 | ->run(); 25 | $this->taskGitHubRelease(\Twinbit\DropdockRunner::VERSION) 26 | ->uri('twinbit/dropdock') 27 | ->askDescription() 28 | ->run(); 29 | $this->pharPublish(); 30 | $this->versionBump(); 31 | } 32 | 33 | /** 34 | * Build the Dropdock phar package 35 | */ 36 | public function pharBuild() 37 | { 38 | $yaml = new Parser(); 39 | $packer = $this->taskPackPhar('dropdock.phar'); 40 | // $packer->compress(TRUE); 41 | $this->taskComposerInstall() 42 | ->noDev() 43 | ->printed(false) 44 | ->run(); 45 | 46 | // Add php sources. 47 | $files = Finder::create()->ignoreVCS(true) 48 | ->files() 49 | ->name('*.php') 50 | ->path('php-src') 51 | ->path('vendor') 52 | ->notPath('data') 53 | ->notPath('tmp') 54 | ->in(__DIR__); 55 | foreach ($files as $file) { 56 | $packer->addFile($file->getRelativePathname(), $file->getRealPath()); 57 | } 58 | 59 | // Add binaries yaml config. 60 | $files = Finder::create()->ignoreVCS(true) 61 | ->files() 62 | ->name('binaries.yml') 63 | ->in(__DIR__); 64 | foreach ($files as $file) { 65 | $packer->addFile($file->getRelativePathname(), $file->getRealPath()); 66 | } 67 | 68 | // Add dropdock binary and make it as executable. 69 | $packer->addFile('DropdockRoboFile.php', 'DropdockRoboFile.php'); 70 | // Add docker-compose.yml. 71 | $packer->addFile('docker-compose.yml.dist', 'docker-compose.yml.dist'); 72 | 73 | // Add boot2local.sh script. 74 | $packer->addFile('src/scripts/boot2local.sh', 'src/scripts/boot2local.sh'); 75 | 76 | $packer->addFile('dropdock', 'dropdock') 77 | ->executable('dropdock') 78 | ->run(); 79 | $this->taskComposerInstall() 80 | ->printed(false) 81 | ->run(); 82 | } 83 | 84 | public function pharPublish() 85 | { 86 | $this->pharBuild(); 87 | rename('dropdock.phar', 'dropdock-release.phar'); 88 | $this->taskGitStack()->checkout('gh-pages')->run(); 89 | rename('dropdock-release.phar', 'dropdock.phar'); 90 | $this->taskGitStack() 91 | ->add('dropdock.phar') 92 | ->commit('dropdock.phar published') 93 | ->push('origin','gh-pages') 94 | ->checkout('master') 95 | ->run(); 96 | } 97 | 98 | public function versionBump($version = null) 99 | { 100 | if (!$version) { 101 | $versionParts = explode('.', \Twinbit\dropdockRunner::VERSION); 102 | $versionParts[count($versionParts)-1]++; 103 | $version = implode('.', $versionParts); 104 | } 105 | $this->taskReplaceInFile(__DIR__.'/php-src/DropdockRunner.php') 106 | ->from("VERSION = '".\Twinbit\dropdockRunner::VERSION."'") 107 | ->to("VERSION = '".$version."'") 108 | ->run(); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twinbit/dropdock", 3 | "description": "Drupal docker environment", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Paolo Mainardi", 8 | "email": "paolo.mainardi@sparkfabrik.com" 9 | } 10 | ], 11 | "bin":["dropdock"], 12 | "autoload":{ 13 | "psr-4":{ 14 | "Twinbit\\":"php-src" 15 | } 16 | }, 17 | "require": { 18 | "php": ">=5.4.0", 19 | "codegyre/robo": "*", 20 | "symfony/yaml": "*" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docker-compose.yml.dist: -------------------------------------------------------------------------------- 1 | data: 2 | image: twinbit/docker-drupal-data 3 | hostname: data 4 | volumes: 5 | - data:/data 6 | nginx: 7 | image: twinbit/docker-drupal-nginx 8 | hostname: nginx 9 | environment: 10 | - LOCAL_UID=##LOCAL_UID## 11 | - LOCAL_GID=##LOCAL_GID## 12 | links: 13 | - php 14 | volumes_from: 15 | - data 16 | ports: 17 | - "8000:80" 18 | privileged: true 19 | php: 20 | image: twinbit/docker-drupal-php 21 | hostname: php 22 | links: 23 | - mysql 24 | - mailcatcher 25 | - solr 26 | volumes_from: 27 | - data 28 | privileged: true 29 | cli: 30 | image: twinbit/docker-drupal-cli 31 | hostname: cli 32 | environment: 33 | - LOCAL_UID=##LOCAL_UID## 34 | - LOCAL_GID=##LOCAL_GID## 35 | - COMPOSER_CACHE_DIR=/composer-cache 36 | links: 37 | - mysql 38 | - mailcatcher 39 | - solr 40 | volumes_from: 41 | - data 42 | volumes: 43 | - data/var/apps/drush:/home/www-data/.drush 44 | - data/var/cache/composer:/composer-cache 45 | # Add ssh keys to container in order to download private repos. 46 | - data/ssh-keys:/home/www-data/.ssh 47 | privileged: true 48 | mysql: 49 | image: twinbit/docker-drupal-mysql 50 | hostname: mysql 51 | privileged: true 52 | ports: 53 | - "3306:3306" 54 | volumes_from: 55 | - data 56 | mailcatcher: 57 | image: twinbit/docker-drupal-mailcatcher 58 | hostname: mailcatcher 59 | volumes_from: 60 | - data 61 | ports: 62 | - "1080:1080" 63 | solr: 64 | image: twinbit/docker-drupal-solr 65 | hostname: solr 66 | ports: 67 | - "8983:8983" 68 | command: -Xmx1024m -DSTOP.PORT=8079 -DSTOP.KEY=stopkey -jar start.jar 69 | 70 | 71 | -------------------------------------------------------------------------------- /dropdock: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | execute(); 20 | -------------------------------------------------------------------------------- /php-src/DropdockRunner.php: -------------------------------------------------------------------------------- 1 | writeln(" ".self::ROBOFILE." not found in this dir "); 29 | exit; 30 | } 31 | require_once $conf_file; 32 | if (!class_exists(self::ROBOCLASS)) { 33 | $this->writeln("Class ".self::ROBOCLASS." was not loaded"); 34 | return false; 35 | } 36 | return true; 37 | } 38 | 39 | public function execute() 40 | { 41 | register_shutdown_function(array($this, 'shutdown')); 42 | $app = new Application('Dropdock', self::VERSION); 43 | 44 | $loaded = $this->loadRoboFile(); 45 | if (!$loaded) { 46 | $app->add(new Init('init')); 47 | $app->run(); 48 | return; 49 | } 50 | $input = $this->prepareInput(); 51 | 52 | $className = self::ROBOCLASS; 53 | $roboTasks = new $className; 54 | $taskNames = array_filter(get_class_methods(self::ROBOCLASS), function($m) { 55 | return !in_array($m, ['__construct']); 56 | }); 57 | $passThrough = $this->passThroughArgs; 58 | foreach ($taskNames as $taskName) { 59 | $command = $this->createCommand($taskName); 60 | $command->setCode(function(InputInterface $input) use ($roboTasks, $taskName, $passThrough) { 61 | // get passthru args 62 | $args = $input->getArguments(); 63 | array_shift($args); 64 | if ($passThrough) { 65 | $args[key(array_slice($args, -1, 1, TRUE))] = $passThrough; 66 | } 67 | $args[] = $input->getOptions(); 68 | $res = call_user_func_array([$roboTasks, $taskName], $args); 69 | if (is_int($res)) exit($res); 70 | if (is_bool($res)) exit($res ? 0 : 1); 71 | if ($res instanceof Result) exit($res->getExitCode()); 72 | }); 73 | $app->add($command); 74 | } 75 | $app->run($input); 76 | } 77 | } 78 | --------------------------------------------------------------------------------