├── .dockerignore ├── .gitignore ├── Dockerfile ├── README.md ├── capistrano ├── Capfile ├── Gemfile ├── Gemfile.lock ├── config │ ├── app │ │ ├── cadvisor.yml │ │ ├── container-exporter.yml │ │ ├── logspout.yml │ │ ├── nginx.yml │ │ ├── postgres.yml │ │ ├── prometheus.yml │ │ ├── rails-blue.yml │ │ └── rails-green.yml │ ├── deploy.rb │ └── deploy │ │ ├── cadvisor.rb │ │ ├── container-exporter.rb │ │ ├── default.rb │ │ ├── logspout.rb │ │ ├── nginx.rb │ │ ├── postgres.rb │ │ ├── prometheus.rb │ │ ├── rails-blue.rb │ │ └── rails-green.rb ├── lib │ └── capistrano │ │ └── tasks │ │ ├── apps.rb │ │ ├── build.rb │ │ ├── cleanup.rb │ │ ├── deploy.rb │ │ ├── hello.rb │ │ ├── images.rb │ │ ├── login.rb │ │ ├── logs.rb │ │ ├── maintenance.rb │ │ ├── ps.rb │ │ ├── pull.rb │ │ ├── push.rb │ │ ├── run.rb │ │ ├── status.rb │ │ └── unit.rb ├── ssh │ ├── cap.pem │ └── cap.pub └── templates │ ├── container.service.erb │ └── prometheus.conf ├── coreos ├── .env.sample ├── Vagrantfile ├── config.rb └── user-data.yml.erb └── script ├── .gitkeep ├── build ├── run ├── run-postgres └── run-rails /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | README.md 4 | script/* 5 | 6 | # 7 | # OS X 8 | # 9 | .DS_Store 10 | .AppleDouble 11 | .LSOverride 12 | # Icon must end with two \r 13 | Icon 14 | # Thumbnails 15 | ._* 16 | # Files that might appear on external disk 17 | .Spotlight-V100 18 | .Trashes 19 | # Directories potentially created on remote AFP share 20 | .AppleDB 21 | .AppleDesktop 22 | Network Trash Folder 23 | Temporary Items 24 | .apdisk 25 | 26 | # 27 | # Vagrant 28 | # 29 | coreos 30 | .env 31 | .vagrant 32 | 33 | # 34 | # Capistrano 35 | # 36 | capistrano/ssh 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # OS X 3 | # 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | # Icon must end with two \r 8 | Icon 9 | # Thumbnails 10 | ._* 11 | # Files that might appear on external disk 12 | .Spotlight-V100 13 | .Trashes 14 | # Directories potentially created on remote AFP share 15 | .AppleDB 16 | .AppleDesktop 17 | Network Trash Folder 18 | Temporary Items 19 | .apdisk 20 | 21 | # 22 | # CoreOS(Vagrant) 23 | # 24 | .vagrant 25 | user-data 26 | .env 27 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie 2 | MAINTAINER Seigo Uchida (@spesnova) 3 | 4 | WORKDIR /capistrano 5 | 6 | RUN apt-get update && \ 7 | apt-get install \ 8 | ssh \ 9 | ruby -y && \ 10 | rm -rf /var/lib/apt/lists/* && \ 11 | gem install bundler --no-ri --no-rdoc 12 | 13 | ADD capistrano/Gemfile /capistrano/Gemfile 14 | ADD capistrano/Gemfile.lock /capistrano/Gemfile.lock 15 | 16 | RUN bundle install 17 | 18 | ADD capistrano /capistrano 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker Example for Capistrano [![Docker Repository on Quay.io](https://quay.io/repository/spesnova/docker-example-capistrano/status "Docker Repository on Quay.io")](https://quay.io/repository/spesnova/docker-example-capistrano) 2 | An example of use Docker for Capistrano orchestration 3 | -------------------------------------------------------------------------------- /capistrano/Capfile: -------------------------------------------------------------------------------- 1 | # Load DSL and Setup Up Stages 2 | require 'capistrano/setup' 3 | 4 | # Includes default deployment tasks 5 | require "capistrano/console" 6 | 7 | # Loads custom tasks from `lib/capistrano/tasks' if you have any defined. 8 | Dir.glob('lib/capistrano/tasks/*.rb').each { |r| import r } 9 | 10 | # 11 | # Load default stage to skip specifing stage every time 12 | # 13 | invoke "default" 14 | -------------------------------------------------------------------------------- /capistrano/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | ruby "2.1.5" 3 | 4 | gem "capistrano", "3.3.5" 5 | gem "ruby-progressbar", "1.7.1" 6 | -------------------------------------------------------------------------------- /capistrano/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | capistrano (3.3.5) 5 | capistrano-stats (~> 1.1.0) 6 | i18n 7 | rake (>= 10.0.0) 8 | sshkit (~> 1.3) 9 | capistrano-stats (1.1.1) 10 | colorize (0.7.5) 11 | i18n (0.7.0) 12 | net-scp (1.2.1) 13 | net-ssh (>= 2.6.5) 14 | net-ssh (2.9.2) 15 | rake (10.4.2) 16 | ruby-progressbar (1.7.1) 17 | sshkit (1.6.1) 18 | colorize (>= 0.7.0) 19 | net-scp (>= 1.1.2) 20 | net-ssh (>= 2.8.0) 21 | 22 | PLATFORMS 23 | ruby 24 | 25 | DEPENDENCIES 26 | capistrano (= 3.3.5) 27 | ruby-progressbar (= 1.7.1) 28 | -------------------------------------------------------------------------------- /capistrano/config/app/cadvisor.yml: -------------------------------------------------------------------------------- 1 | name: cadvisor 2 | description: cAdvisor 3 | repo: github.com/google/cadvisor 4 | image: google/cadvisor:latest 5 | command: 6 | ports: 7 | - 8080:8080 8 | volumes: 9 | - /etc/nginx/switch:/etc/nginx/switch:ro 10 | - /:/rootfs:ro 11 | - /var/run:/var/run:rw 12 | - /sys:/sys:ro 13 | - /var/lib/docker/:/var/lib/docker:ro 14 | net: 15 | environment: 16 | -------------------------------------------------------------------------------- /capistrano/config/app/container-exporter.yml: -------------------------------------------------------------------------------- 1 | name: container-exporter 2 | description: Prometheus exporter exposing container metrics 3 | repo: github.com/docker-infra/container_exporter 4 | image: prom/container-exporter 5 | command: 6 | ports: 7 | - 9104:9104 8 | volumes: 9 | - /sys/fs/cgroup:/cgroup 10 | - /var/run/docker.sock:/var/run/docker.sock 11 | net: host 12 | environment: 13 | -------------------------------------------------------------------------------- /capistrano/config/app/logspout.yml: -------------------------------------------------------------------------------- 1 | name: logspout 2 | description: Logspout, a log router for Docker container 3 | repo: github.com/gliderlabs/logspout 4 | image: gliderlabs/logspout:latest 5 | command: 6 | ports: 7 | - 8000:8000 8 | volumes: 9 | - /var/run/docker.sock:/tmp/docker.sock 10 | environment: 11 | -------------------------------------------------------------------------------- /capistrano/config/app/nginx.yml: -------------------------------------------------------------------------------- 1 | name: docker-example-nginx 2 | description: Example Nginx Proxy 3 | repo: github.com/spesnova/docker-example-nginx 4 | image: quay.io/spesnova/docker-example-nginx 5 | command: 6 | ports: 7 | volumes: 8 | - /etc/nginx/switch:/etc/nginx/switch:ro 9 | net: host 10 | environment: 11 | - SERVER_NAME=hello.com 12 | -------------------------------------------------------------------------------- /capistrano/config/app/postgres.yml: -------------------------------------------------------------------------------- 1 | name: postgres 2 | description: PostgreSQL 3 | repo: 4 | image: postgres:9.4.0 5 | command: 6 | ports: 7 | - 5432:5432 8 | volumes: 9 | net: 10 | environment: 11 | - POSTGRES_USER=hello 12 | - POSTGRES_PASSWORD=world 13 | -------------------------------------------------------------------------------- /capistrano/config/app/prometheus.yml: -------------------------------------------------------------------------------- 1 | name: prometheus 2 | description: An open-source service monitoring system and time series database 3 | repo: github.com/prometheus/prometheus 4 | image: prom/prometheus 5 | command: -config.file=/prometheus.conf 6 | ports: 7 | - 9090:9090 8 | volumes: 9 | - /home/core/share/capistrano/templates/prometheus.conf:/prometheus.conf 10 | net: host 11 | environment: 12 | -------------------------------------------------------------------------------- /capistrano/config/app/rails-blue.yml: -------------------------------------------------------------------------------- 1 | name: docker-example-rails-blue 2 | description: Example Rails App (blue) 3 | repo: github.com/spesnova/docker-example-rails 4 | image: quay.io/spesnova/docker-example-rails 5 | command: 6 | ports: 7 | - 8091:3000 8 | volumes: 9 | net: 10 | environment: 11 | - DATABASE_HOST=172.17.8.101 12 | - DATABASE_PORT=5432 13 | - DATABASE_USER=hello 14 | - DATABASE_PASSWORD=world 15 | - SECRET_KEY_BASE=450a851180c712e6a7ba6f4ab4a9624caddfc02d842eef3315cc47f9b0a16ef3cb5e5b68184d998604076a05d32d108b465f7bfe23623222690be720c7bfd39c 16 | - RACK_ENV=production 17 | - RAILS_SERVE_STATIC_FILES=true 18 | - COLOR=blue 19 | -------------------------------------------------------------------------------- /capistrano/config/app/rails-green.yml: -------------------------------------------------------------------------------- 1 | name: docker-example-rails-green 2 | description: Example Rails App (green) 3 | repo: github.com/spesnova/docker-example-rails 4 | image: quay.io/spesnova/docker-example-rails 5 | command: 6 | ports: 7 | - 8092:3000 8 | volumes: 9 | net: 10 | environment: 11 | - DATABASE_HOST=172.17.8.101 12 | - DATABASE_PORT=5432 13 | - DATABASE_USER=hello 14 | - DATABASE_PASSWORD=world 15 | - SECRET_KEY_BASE=450a851180c712e6a7ba6f4ab4a9624caddfc02d842eef3315cc47f9b0a16ef3cb5e5b68184d998604076a05d32d108b465f7bfe23623222690be720c7bfd39c 16 | - RACK_ENV=production 17 | - RAILS_SERVE_STATIC_FILES=true 18 | - COLOR=green 19 | -------------------------------------------------------------------------------- /capistrano/config/deploy.rb: -------------------------------------------------------------------------------- 1 | require "yaml" 2 | 3 | # 4 | # Capistrano Version 5 | # 6 | lock "3.3.5" 7 | 8 | # 9 | # Output 10 | # 11 | set :format, :pretty 12 | set :pty, true 13 | 14 | # 15 | # Log Level 16 | # 17 | set :log_level, case ENV["LOG_LEVEL"] 18 | when "trace" then :trace 19 | when "debug" then :debug 20 | when "info" then :info 21 | when "warn" then :warn 22 | when "error" then :error 23 | when "fatal" then :fatal 24 | else :warn 25 | end 26 | 27 | # 28 | # SSH Options 29 | # 30 | set :ssh_options, { 31 | user: "cap", 32 | keys: ["/capistrano/ssh/cap.pem"], 33 | forward_agent: true, 34 | auth_methods: %w(publickey) 35 | } 36 | 37 | # 38 | # Servers 39 | # 40 | server "172.17.8.101" 41 | server "172.17.8.102" 42 | server "172.17.8.103" 43 | 44 | # 45 | # Roles 46 | # 47 | role "cap", ["172.17.8.101"] 48 | role "build", ["172.17.8.101"] 49 | role "postgres", ["172.17.8.101"] 50 | role "prometheus", ["172.17.8.101"] 51 | role "container-exporter", ["172.17.8.101"] 52 | role "nginx", ["172.17.8.102", "172.17.8.103"] 53 | role "rails-blue", ["172.17.8.102", "172.17.8.103"] 54 | role "rails-green", ["172.17.8.102", "172.17.8.103"] 55 | role "cadvisor", ["172.17.8.101", "172.17.8.102", "172.17.8.103"] 56 | role "logspout", ["172.17.8.101", "172.17.8.102", "172.17.8.103"] 57 | 58 | # 59 | # Docker Remote API 60 | # 61 | set :api_endpoint, "http://localhost:2375" 62 | set :api_version, "v1.16" 63 | 64 | # 65 | # Helpers 66 | # 67 | def load_app_config 68 | config = YAML.load_file("config/app/#{fetch(:stage).to_s}.yml") 69 | 70 | if config["name"].nil? || config["name"].empty? 71 | abort "App name is required! Please specify it in your yaml" 72 | end 73 | options = ["--name #{config['name']}"] 74 | 75 | unless config["environment"].nil? || config["environment"].empty? 76 | options += config["environment"].map { |env| "-e #{env}" } 77 | end 78 | 79 | unless config["volumes"].nil? || config["volumes"].empty? 80 | options += config["volumes"].map { |vol| "-v #{vol}" } 81 | end 82 | 83 | unless config["ports"].nil? || config["ports"].empty? 84 | options += config["ports"].map { |port| "-p #{port}" } 85 | end 86 | 87 | unless config["net"].nil? || config["net"].empty? 88 | options << "--net=#{config['net']}" 89 | end 90 | 91 | set :description, config["description"] 92 | set :container, config["name"] 93 | set :image, config["image"] 94 | set :options, options.join(" ") 95 | set :command, config["command"] 96 | set :repo, config["repo"] 97 | end 98 | -------------------------------------------------------------------------------- /capistrano/config/deploy/cadvisor.rb: -------------------------------------------------------------------------------- 1 | set :stage, "cadvisor" 2 | load_app_config 3 | -------------------------------------------------------------------------------- /capistrano/config/deploy/container-exporter.rb: -------------------------------------------------------------------------------- 1 | set :stage, "container-exporter" 2 | load_app_config 3 | -------------------------------------------------------------------------------- /capistrano/config/deploy/default.rb: -------------------------------------------------------------------------------- 1 | set :stage, "default" 2 | -------------------------------------------------------------------------------- /capistrano/config/deploy/logspout.rb: -------------------------------------------------------------------------------- 1 | set :stage, "logspout" 2 | load_app_config 3 | -------------------------------------------------------------------------------- /capistrano/config/deploy/nginx.rb: -------------------------------------------------------------------------------- 1 | set :stage, "nginx" 2 | load_app_config 3 | -------------------------------------------------------------------------------- /capistrano/config/deploy/postgres.rb: -------------------------------------------------------------------------------- 1 | set :stage, "postgres" 2 | load_app_config 3 | -------------------------------------------------------------------------------- /capistrano/config/deploy/prometheus.rb: -------------------------------------------------------------------------------- 1 | set :stage, :prometheus 2 | load_app_config 3 | -------------------------------------------------------------------------------- /capistrano/config/deploy/rails-blue.rb: -------------------------------------------------------------------------------- 1 | set :stage, "rails-blue" 2 | load_app_config 3 | -------------------------------------------------------------------------------- /capistrano/config/deploy/rails-green.rb: -------------------------------------------------------------------------------- 1 | set :stage, "rails-green" 2 | load_app_config 3 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/apps.rb: -------------------------------------------------------------------------------- 1 | desc "List apps (stage)" 2 | task :apps do 3 | puts stages.reject!{|s| s == "default"} 4 | end 5 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/build.rb: -------------------------------------------------------------------------------- 1 | desc "Build docker image for an app" 2 | task :build do 3 | image = fetch(:image) 4 | repo = fetch(:repo) 5 | branch = ENV["BRANCH"] || "master" 6 | src_path = "/home/cap/src/#{repo}" 7 | 8 | output = "Building #{image}..." 9 | 10 | progressbar_thread = Thread.new do 11 | options = { 12 | title: output, 13 | total: nil, 14 | length: (output.length + 4), 15 | format: "%t %B", 16 | unknown_progress_animation_steps: ['o..', '.o.', '..o'], 17 | } 18 | progressbar = ProgressBar.create(options) 19 | 20 | loop do 21 | sleep 0.3 22 | progressbar.increment 23 | end 24 | end 25 | 26 | execution_thread = Thread.new do 27 | on roles(:build) do 28 | unless test("ls #{src_path}/.git") 29 | execute("git clone http://#{repo}.git #{src_path}") 30 | end 31 | 32 | # FIXME: within syntax doesn't work for me :( 33 | execute("cd #{src_path} && git fetch -p") 34 | execute("cd #{src_path} && git checkout #{branch}") 35 | execute("cd #{src_path} && git pull origin #{branch}") 36 | 37 | if test("ls #{src_path}/script/build") 38 | execute("#{src_path}/script/build") 39 | else 40 | execute("cd #{src_path} && docker build #{image} .") 41 | end 42 | end 43 | progressbar_thread.kill 44 | end 45 | 46 | progressbar_thread.join 47 | execution_thread.join 48 | 49 | puts "#{output} done" 50 | end 51 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/cleanup.rb: -------------------------------------------------------------------------------- 1 | desc "Remove untagged images and exited containers" 2 | task :cleanup do 3 | invoke "cleanup:images" 4 | invoke "cleanup:containers" 5 | end 6 | 7 | namespace :cleanup do 8 | desc "Remove untagged images" 9 | task :images do 10 | print "Cleaning up untagged images... " 11 | on roles(:all) do 12 | execute('docker rmi $(docker images -f "dangling=true" -q) || true') 13 | end 14 | puts "done" 15 | end 16 | 17 | desc "Remove exited containers" 18 | task :containers do 19 | print "Cleaning up exited containers... " 20 | on roles(:all) do 21 | execute('docker rm $(docker ps -afq status=exited) || true') 22 | end 23 | puts "done" 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/deploy.rb: -------------------------------------------------------------------------------- 1 | def current_color 2 | to = "" 3 | on roles(:cap) do 4 | to = test("ls /etc/nginx/switch/blue") ? "blue" : "green" 5 | end 6 | to 7 | end 8 | 9 | def next_color 10 | to = "" 11 | on roles(:cap) do 12 | to = test("ls /etc/nginx/switch/blue") ? "green" : "blue" 13 | end 14 | to 15 | end 16 | 17 | desc "Deploy an app" 18 | task :deploy do 19 | invoke "pull" 20 | invoke "unit:reload" 21 | invoke "ps:restart" 22 | end 23 | 24 | namespace :deploy do 25 | desc "Switch to blue/green containers" 26 | task :switch, :to do |t, args| 27 | to = "" 28 | to = args[:to] if args[:to] == "blue" || args[:to] == "green" 29 | to = next_color if to == "" 30 | 31 | from = "blue" 32 | from = "green" if to == "blue" 33 | 34 | print "Swiching to #{to} containers... " 35 | 36 | on roles(:all) do 37 | execute("sudo mkdir -pv /etc/nginx/switch || true") 38 | execute("sudo touch /etc/nginx/switch/#{to}") 39 | execute("sudo rm /etc/nginx/switch/#{from} || true") 40 | end 41 | 42 | puts "done" 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/hello.rb: -------------------------------------------------------------------------------- 1 | desc "Hello World" 2 | task :hello do 3 | on roles(:all) do 4 | puts capture('echo "Hello from $(hostname) !"') 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/images.rb: -------------------------------------------------------------------------------- 1 | desc "List docker images per host" 2 | task :images do 3 | machines = [] 4 | 5 | on roles(:all) do |m| 6 | machines << { 7 | ip: m.hostname, 8 | images_json: capture("curl #{fetch(:api_endpoint)}/#{fetch(:api_version)}/images/json") 9 | } 10 | end 11 | 12 | rows = [] 13 | machines.each do |m| 14 | JSON.parse(m[:images_json]).each do |c| 15 | rows << [m[:ip], c["RepoTags"].first, c["Id"].slice!(0..6), Time.at(c["Created"]).strftime("%Y/%m/%d/%H:%M")] 16 | end 17 | end 18 | 19 | rows.sort_by!{|row| row[1]} 20 | rows.unshift(["MACHINE", "IMAGE", "ID", "CREATED"]) 21 | rows.each do |r| 22 | puts r[0].ljust(15) + r[1].ljust(50) + r[2].ljust(10) + r[3].ljust(25) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/login.rb: -------------------------------------------------------------------------------- 1 | desc "login to docker registry" 2 | task :login do 3 | ask(:Registry, "quay.io", echo: true) 4 | ask(:Username, nil, echo: true) 5 | ask(:Password, nil, echo: false) 6 | ask(:Email, nil, echo: true) 7 | 8 | registry = fetch(:Registry) 9 | username = fetch(:Username) 10 | password = fetch(:Password) 11 | email = fetch(:Email) 12 | 13 | args = [ 14 | "--username=#{username}", 15 | "--password=#{password}", 16 | "--email=#{email}", 17 | registry, 18 | ].join(" ") 19 | 20 | on roles(:all) do |m| 21 | if test("docker login #{args}") 22 | puts [m.hostname, "Login Succeeded"].join(" ") 23 | else 24 | puts [m.hostname, "Login Failed"].join(" ") 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/logs.rb: -------------------------------------------------------------------------------- 1 | require "net/http" 2 | 3 | def puts_log_stream(endpoint) 4 | uri = URI.parse(endpoint) 5 | Net::HTTP.start(uri.host, uri.port) do |http| 6 | request = Net::HTTP::Get.new uri.request_uri 7 | 8 | http.request request do |response| 9 | response.read_body do |chunk| 10 | puts "#{uri.host}|#{chunk}" 11 | end 12 | end 13 | end 14 | end 15 | 16 | desc "Display continually stream logs" 17 | task :logs do 18 | puts "Type CTRL+C to stop streaming" 19 | 20 | filter = "" 21 | filter = fetch(:container) unless fetch(:stage) == "hidden" 22 | filter = ENV['FILTER'] unless ENV['FILTER'].nil? || ENV['FILTER'].empty? 23 | filter = "filter:#{filter}" unless filter == "" 24 | 25 | begin 26 | threads = [] 27 | roles(:all).each do |m| 28 | threads << Thread.new do 29 | puts_log_stream(["http://#{m.hostname}:8000/logs", filter].join("/")) 30 | end 31 | end 32 | threads.each { |t| t.join } 33 | rescue Interrupt 34 | puts 35 | puts " ! Command cancelled." 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/maintenance.rb: -------------------------------------------------------------------------------- 1 | namespace :maintenance do 2 | desc "Enable to maintenance mode" 3 | task :on do 4 | print "Enabling maintenance mode... " 5 | on roles(:all) do 6 | execute("sudo mkdir -pv /etc/nginx/switch || true") 7 | execute("sudo touch /etc/nginx/switch/maintenance") 8 | end 9 | puts "done" 10 | end 11 | 12 | desc "Disable to maintenance mode" 13 | task :off do 14 | print "Disabling maintenance mode... " 15 | on roles(:all) do 16 | execute("sudo mkdir -pv /etc/nginx/switch || true") 17 | execute("sudo rm /etc/nginx/switch/maintenance || true") 18 | end 19 | puts "done" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/ps.rb: -------------------------------------------------------------------------------- 1 | require "erb" 2 | require "json" 3 | 4 | desc "List containers for an app" 5 | task :ps do 6 | machines = [] 7 | 8 | on roles(:all) do |m| 9 | machines << { 10 | ip: m.hostname, 11 | ps_json: capture("curl #{fetch(:api_endpoint)}/#{fetch(:api_version)}/containers/json?all=true") 12 | } 13 | end 14 | 15 | rows = [] 16 | machines.each do |m| 17 | JSON.parse(m[:ps_json]).each do |c| 18 | ports = "" 19 | c["Ports"].each do |port| 20 | ports << "#{port['IP']}:#{port['PublicPort']}->#{port['PrivatePort']}/#{port['Type']}" 21 | end 22 | rows << [m[:ip], c["Id"].slice!(0..6), c["Names"].first.sub(/\//,''), c["Status"], ports, c["Command"]] 23 | end 24 | end 25 | 26 | rows.sort_by!{|row| row[2]} 27 | rows.sort_by!{|row| row[0]} if ENV["SORT_BY"] == "host" 28 | rows.unshift(["MACHINE", "ID", "NAME", "STATUS", "PORTS", "COMMAND"]) 29 | rows.each do |r| 30 | puts r[0].ljust(15) + r[1].ljust(10) + r[2].ljust(30) + r[3].ljust(25) + r[4].ljust(25) + r[5] 31 | end 32 | end 33 | 34 | namespace :ps do 35 | desc "Start containers for an app" 36 | task :start do 37 | container = fetch(:container) 38 | print "Starting #{container}... " 39 | on roles(fetch(:stage)) do 40 | execute("sudo systemctl enable #{container}.service") 41 | execute("sudo systemctl start #{container}.service") 42 | end 43 | puts "done" 44 | end 45 | 46 | desc "Restart containers for an app" 47 | task :restart do 48 | container = fetch(:container) 49 | print "Restarting #{container}... " 50 | on roles(fetch(:stage)) do 51 | execute("sudo systemctl restart #{container}.service") 52 | end 53 | puts "done" 54 | end 55 | 56 | desc "Stop containers for an app" 57 | task :stop do 58 | container = fetch(:container) 59 | print "Stopping #{container}... " 60 | on roles(fetch(:stage)) do 61 | execute("sudo systemctl stop #{container}.service") 62 | end 63 | puts "done" 64 | end 65 | 66 | desc "Kill containers for an app" 67 | task :kill do 68 | container = fetch(:container) 69 | print "Killing #{container}... " 70 | on roles(fetch(:stage)) do 71 | execute("sudo systemctl kill #{container}.service") 72 | end 73 | puts "done" 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/pull.rb: -------------------------------------------------------------------------------- 1 | require "ruby-progressbar" 2 | 3 | desc "Pull docker image for an app" 4 | task :pull do 5 | image = fetch(:image) 6 | output = "Pulling #{image}..." 7 | 8 | progressbar_thread = Thread.new do 9 | options = { 10 | title: output, 11 | total: nil, 12 | length: (output.length + 4), 13 | format: "%t %B", 14 | unknown_progress_animation_steps: ['o..', '.o.', '..o'], 15 | } 16 | progressbar = ProgressBar.create(options) 17 | 18 | loop do 19 | sleep 0.3 20 | progressbar.increment 21 | end 22 | end 23 | 24 | execution_thread = Thread.new do 25 | on roles(:all) do 26 | unless test("docker pull #{image}") 27 | progressbar_thread.kill 28 | puts "" 29 | abort "Failed to pull" 30 | end 31 | end 32 | progressbar_thread.kill 33 | end 34 | 35 | progressbar_thread.join 36 | execution_thread.join 37 | 38 | puts "#{output} done" 39 | end 40 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/push.rb: -------------------------------------------------------------------------------- 1 | desc "Push docker image to registry" 2 | task :push do 3 | image = fetch(:image) 4 | output = "Pushing #{image}..." 5 | 6 | progressbar_thread = Thread.new do 7 | options = { 8 | title: output, 9 | total: nil, 10 | length: (output.length + 4), 11 | format: "%t %B", 12 | unknown_progress_animation_steps: ['o..', '.o.', '..o'], 13 | } 14 | progressbar = ProgressBar.create(options) 15 | 16 | loop do 17 | sleep 0.3 18 | progressbar.increment 19 | end 20 | end 21 | 22 | execution_thread = Thread.new do 23 | on roles(:build) do 24 | unless test("docker push #{image}") 25 | progressbar_thread.kill 26 | puts "" 27 | abort "Failed to push" 28 | end 29 | end 30 | progressbar_thread.kill 31 | end 32 | 33 | progressbar_thread.join 34 | execution_thread.join 35 | 36 | puts "#{output} done" 37 | end 38 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/run.rb: -------------------------------------------------------------------------------- 1 | desc "Run one-off container for an app" 2 | task :run do 3 | if fetch(:stage) == "default" 4 | abort "Please specify app to run. Example: $ cap rails-blue run" 5 | end 6 | 7 | ask(:command, "/bin/bash", echo: true) 8 | 9 | container = "#{fetch(:container)}.run.#{Time.now.to_i}" 10 | image = fetch(:image) 11 | options = fetch(:options) 12 | command = fetch(:command) 13 | 14 | docker_command = [ 15 | "/usr/bin/docker", 16 | "run", 17 | "-it", 18 | "--rm", 19 | "--name #{container}", 20 | "#{options}", 21 | "#{image}", 22 | "#{command}", 23 | ].join(" ") 24 | 25 | ssh_command = [ 26 | "ssh", 27 | "-t", 28 | "-i #{fetch(:ssh_options)[:keys].first}", 29 | "-o StrictHostKeyChecking=no", 30 | "-o UserKnownHostsFile=/dev/null", 31 | "-o LogLevel=quiet", 32 | "#{fetch(:ssh_options)[:user]}@#{roles(:cap).first.hostname}", 33 | "'#{docker_command}'", 34 | ].join(" ") 35 | 36 | puts "Running #{command}... up, #{container}" 37 | exec(ssh_command) 38 | end 39 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/status.rb: -------------------------------------------------------------------------------- 1 | desc "Show color(blue/green) and maintenance mode(on/off)" 2 | task :status do 3 | maintenance = false 4 | on roles(:cap) do 5 | maintenance = test("ls /etc/nginx/switch/maintenance") 6 | end 7 | puts "Maintenance Mode: #{maintenance}" 8 | puts "Current Color: #{current_color}" 9 | end 10 | -------------------------------------------------------------------------------- /capistrano/lib/capistrano/tasks/unit.rb: -------------------------------------------------------------------------------- 1 | namespace :unit do 2 | desc "Load/Reload unit file" 3 | task :reload do 4 | description = fetch(:description) 5 | container = fetch(:container) 6 | image = fetch(:image) 7 | options = fetch(:options) 8 | command = fetch(:command) 9 | 10 | print "Reloading #{container}... " 11 | 12 | template_path = ::File.expand_path("../../../../templates/container.service.erb", __FILE__) 13 | template = ::ERB.new(File.new(template_path).read).result(binding) 14 | tmp_path = "/tmp/#{container}.service" 15 | dest_path = "/etc/systemd/system/#{container}.service" 16 | 17 | on roles(:all) do 18 | upload!(StringIO.new(template), tmp_path) 19 | execute("sudo cp #{tmp_path} #{dest_path}") 20 | execute("sudo chmod 644 #{dest_path}") 21 | execute("sudo chown root:root #{dest_path}") 22 | execute("sudo systemctl daemon-reload") 23 | end 24 | 25 | puts "done" 26 | end 27 | 28 | desc "Cat systemd unit file on each machine for an app" 29 | task :cat do 30 | container = fetch(:container) 31 | target_path = "/etc/systemd/system/#{container}.service" 32 | dest_path = "/tmp/#{container}.service" 33 | 34 | on roles(:all, in: :sequence) do |m| 35 | if test("ls #{target_path}") 36 | download!(target_path, dest_path) 37 | puts "" 38 | puts "----- #{m.hostname} --------------------------------------" 39 | puts File.new(dest_path).read 40 | puts "---------------------------------------------------------" 41 | puts "" 42 | else 43 | puts "" 44 | puts "----- #{m.hostname} --------------------------------------" 45 | puts "---------------------------------------------------------" 46 | puts "" 47 | end 48 | end 49 | end 50 | 51 | desc "Cat generated unit file for checking" 52 | task :check do 53 | description = fetch(:description) 54 | container = fetch(:container) 55 | image = fetch(:image) 56 | options = fetch(:options) 57 | command = fetch(:command) 58 | 59 | template_path = ::File.expand_path("../../../../templates/container.service.erb", __FILE__) 60 | puts ::ERB.new(File.new(template_path).read).result(binding) 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /capistrano/ssh/cap.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAwREKvw/JX01SHjNnEmXlFHv8bfX6h6UEtq4J6djC1V8oMaJP 3 | ORfPPv64UwLbmjWL4a31dEBJY6OKcv3Gzjf68n54hxgKRLpk/nlWXiVsICmkNnUn 4 | 6sqV46LieSTyER0C6m6Lhj8PqIRREXrTCxrtvdKjdNF81K1Z1uBERU6zFZIpMhTe 5 | uvM1YrhnPimjjva1xcoCBD7pXtonANhvrvH/WvwcmOp8Yvdl0Bw3V1TDdTitLu0L 6 | Sfv0KxWcd04HZx51Ya7wkKgDZTlSe8WqlsquAMBTT3BnwUlDD3B4e88Mil0/4nwR 7 | bgkrVWr5wqZcqsUm4H6kG2NEkWQilnUV4v+fDQIDAQABAoIBAFpmv3BtVO5iBySL 8 | DyVHPvfTgoR+nDutokJjxdKQo9JDR0/OX2gtZOZrYSXFfcx8bC5VRUyU2YhlSGvF 9 | trRS9Bdd7tPbBtvdp3KcoDtfLHz24qR5QSKoj3zShVcSXKJ0wivBbWWD27IdmtQj 10 | ffSCPHYYzl7hxKDVNu7tfioxyps7TqXdQNGqOHedspVwniWzHi6UcYzteHzpLarA 11 | 5eBG3l3eOvzeNui50OLWK3Jt+1nG/5SbKkOwEeABh58vPtBCBZFzmXMTUIvU9wZm 12 | asyR0Frhtarqy2hmvTe3q0MbR/kM3br8WfvuncyZfUKQUDMs78sBADvrWh6u+ezq 13 | +pLgtyUCgYEA+Yuwo5nlHHvy21aNudxiolAxvJSf/43vyvYX15jFXgocIuBUWvOz 14 | Qir1Mfu2gbdH9iN6SgcFIAGPVKNu+LmN7VCX9eEGZfl1KF30zreJy6pjx49ZVi3F 15 | GFBuuotBmstbVifkhUk1RshveJLjCCVvis7982W+yEs707voSCDDli8CgYEAxg9j 16 | cw55+Gr8wQ+ImHdLva+3/NAw5EYLSCEnrtOFgw1heV+/ZtwV2eCKbwZU0khWB3ng 17 | mVhNDM5F7EGy4GYqDEE7U9OBURRTj7j6ldr13Mz0fOVVqH68AVCBdnCRn4afjQOL 18 | b0bzdla/LKDuByrArMdKlqg/jTvP7LdBKxw2S4MCgYEApOd2tuX/zS7rcZ5k0amd 19 | VH2CIIhmos385DZz0vkVk+tCZJmxpNjeYJ9aoMkh9d5UI4eWTE0PSfM98ESAFMUp 20 | 0OUtRkKJo+GRVjegiuommPvkK//CnXxpfoPIaGWV2OEBXpHGJX4XQss5PohylvOG 21 | Hkhi8PEPffSZeHX4LZHZLekCgYBNOh7a9CAW/xCC7t2iJZIA6o1hJISL3cv0Wgkx 22 | IAUFLqh9PRpSrypOBEG2PM/CFraEv78Vy9pvTdbx4kQvP2bR1HWfn+7igHx8o/IB 23 | kJkheUEzmfCmfJQuJwfz+LyvaTy5LVKnFxFDaVutuSpW3RK3zBWHXR86oMHYWTQt 24 | 7Rg2pQKBgQDK9E2rqySnqd1Dp7J18HOsxlpGDerIS/eZBy8D3x8B4aJ2/JbulTKb 25 | uL1etfws7kPZUZEKpzARtWQyQDlo/GH0epxAYlGGkopmc6hYhpT+XN04Zb6hgdeb 26 | ieinIB1oDbC3dQPbSX28HsdAWPTbutwBwoTDqwNLPkw+H4MwwJioOw== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /capistrano/ssh/cap.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBEQq/D8lfTVIeM2cSZeUUe/xt9fqHpQS2rgnp2MLVXygxok85F88+/rhTAtuaNYvhrfV0QEljo4py/cbON/ryfniHGApEumT+eVZeJWwgKaQ2dSfqypXjouJ5JPIRHQLqbouGPw+ohFERetMLGu290qN00XzUrVnW4ERFTrMVkikyFN668zViuGc+KaOO9rXFygIEPule2icA2G+u8f9a/ByY6nxi92XQHDdXVMN1OK0u7QtJ+/QrFZx3TgdnHnVhrvCQqANlOVJ7xaqWyq4AwFNPcGfBSUMPcHh7zwyKXT/ifBFuCStVavnCplyqxSbgfqQbY0SRZCKWdRXi/58N seigo@rb9.local 2 | -------------------------------------------------------------------------------- /capistrano/templates/container.service.erb: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=<%= description %> 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | ExecStartPre=-/usr/bin/docker kill <%= container %> 8 | ExecStartPre=-/usr/bin/docker rm <%= container %> 9 | ExecStart=/usr/bin/docker run <%= options %> <%= image %> <%= command %> 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /capistrano/templates/prometheus.conf: -------------------------------------------------------------------------------- 1 | global: { 2 | scrape_interval: "15s" 3 | evaluation_interval: "15s" 4 | labels: { 5 | label: { 6 | name: "monitor" 7 | value: "web-monitor" 8 | } 9 | } 10 | } 11 | 12 | job: { 13 | name: "prometheus" 14 | scrape_interval: "5s" 15 | target_group: { 16 | target: "http://localhost:9090/metrics" 17 | } 18 | } 19 | 20 | job: { 21 | name: "container-exporter" 22 | scrape_interval: "5s" 23 | target_group: { 24 | target: "http://localhost:9104/metrics" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /coreos/.env.sample: -------------------------------------------------------------------------------- 1 | TIMEZONE=Asia/Tokyo 2 | COMPOSE_VERSION=1.1.0 3 | -------------------------------------------------------------------------------- /coreos/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # # vi: set ft=ruby : 3 | 4 | require 'fileutils' 5 | 6 | Vagrant.require_version ">= 1.6.0" 7 | 8 | CLOUD_CONFIG_PATH = File.join(File.dirname(__FILE__), "user-data") 9 | CONFIG = File.join(File.dirname(__FILE__), "config.rb") 10 | 11 | # Defaults for config options defined in CONFIG 12 | $num_instances = 1 13 | $update_channel = "alpha" 14 | $enable_serial_logging = false 15 | $vb_gui = false 16 | $vb_memory = 1024 17 | $vb_cpus = 1 18 | 19 | # Attempt to apply the deprecated environment variable NUM_INSTANCES to 20 | # $num_instances while allowing config.rb to override it 21 | if ENV["NUM_INSTANCES"].to_i > 0 && ENV["NUM_INSTANCES"] 22 | $num_instances = ENV["NUM_INSTANCES"].to_i 23 | end 24 | 25 | if File.exist?(CONFIG) 26 | require CONFIG 27 | end 28 | 29 | Vagrant.configure("2") do |config| 30 | # always use Vagrants insecure key 31 | config.ssh.insert_key = false 32 | 33 | config.vm.box = "coreos-%s" % $update_channel 34 | config.vm.box_version = ">= 308.0.1" 35 | config.vm.box_url = "http://%s.release.core-os.net/amd64-usr/current/coreos_production_vagrant.json" % $update_channel 36 | 37 | config.vm.provider :vmware_fusion do |vb, override| 38 | override.vm.box_url = "http://%s.release.core-os.net/amd64-usr/current/coreos_production_vagrant_vmware_fusion.json" % $update_channel 39 | end 40 | 41 | config.vm.provider :virtualbox do |v| 42 | # On VirtualBox, we don't have guest additions or a functional vboxsf 43 | # in CoreOS, so tell Vagrant that so it can be smarter. 44 | v.check_guest_additions = false 45 | v.functional_vboxsf = false 46 | end 47 | 48 | # plugin conflict 49 | if Vagrant.has_plugin?("vagrant-vbguest") then 50 | config.vbguest.auto_update = false 51 | end 52 | 53 | (1..$num_instances).each do |i| 54 | config.vm.define vm_name = "core-%02d" % i do |config| 55 | config.vm.hostname = vm_name 56 | 57 | if $enable_serial_logging 58 | logdir = File.join(File.dirname(__FILE__), "log") 59 | FileUtils.mkdir_p(logdir) 60 | 61 | serialFile = File.join(logdir, "%s-serial.txt" % vm_name) 62 | FileUtils.touch(serialFile) 63 | 64 | config.vm.provider :vmware_fusion do |v, override| 65 | v.vmx["serial0.present"] = "TRUE" 66 | v.vmx["serial0.fileType"] = "file" 67 | v.vmx["serial0.fileName"] = serialFile 68 | v.vmx["serial0.tryNoRxLoss"] = "FALSE" 69 | end 70 | 71 | config.vm.provider :virtualbox do |vb, override| 72 | vb.customize ["modifyvm", :id, "--uart1", "0x3F8", "4"] 73 | vb.customize ["modifyvm", :id, "--uartmode1", serialFile] 74 | end 75 | end 76 | 77 | if $expose_docker_tcp 78 | config.vm.network "forwarded_port", guest: 2375, host: ($expose_docker_tcp + i - 1), auto_correct: true 79 | end 80 | 81 | config.vm.provider :vmware_fusion do |vb| 82 | vb.gui = $vb_gui 83 | end 84 | 85 | config.vm.provider :virtualbox do |vb| 86 | vb.gui = $vb_gui 87 | vb.memory = $vb_memory 88 | vb.cpus = $vb_cpus 89 | end 90 | 91 | ip = "172.17.8.#{i+100}" 92 | config.vm.network :private_network, ip: ip 93 | 94 | # Uncomment below to enable NFS for sharing the host machine into the coreos-vagrant VM. 95 | config.vm.synced_folder "../", "/home/core/#{File.basename(File.dirname(Dir.pwd))}", id: "core", :nfs => true, :mount_options => ['nolock,vers=3,udp'] 96 | 97 | if File.exist?(CLOUD_CONFIG_PATH) 98 | config.vm.provision :file, :source => "#{CLOUD_CONFIG_PATH}", :destination => "/tmp/vagrantfile-user-data" 99 | config.vm.provision :shell, :inline => "mv /tmp/vagrantfile-user-data /var/lib/coreos-vagrant/", :privileged => true 100 | end 101 | 102 | end 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /coreos/config.rb: -------------------------------------------------------------------------------- 1 | require 'erb' 2 | require 'dotenv' 3 | 4 | # Create user-data from erb template 5 | Dotenv.load 6 | erb = File.open(File.join(File.dirname(__FILE__), "user-data.yml.erb")) { |f| ERB.new(f.read) } 7 | File.write(File.join(File.dirname(__FILE__), "user-data"), erb.result(binding)) 8 | 9 | # To automatically replace the discovery token on 'vagrant up', uncomment 10 | # the lines below: 11 | # 12 | #if File.exists?('user-data') && ARGV[0].eql?('up') 13 | # require 'open-uri' 14 | # require 'yaml' 15 | # 16 | # token = open('https://discovery.etcd.io/new').read 17 | # 18 | # data = YAML.load(IO.readlines('user-data')[1..-1].join) 19 | # data['coreos']['etcd']['discovery'] = token 20 | # 21 | # yaml = YAML.dump(data) 22 | # File.open('user-data', 'w') { |file| file.write("#cloud-config\n\n#{yaml}") } 23 | #end 24 | # 25 | 26 | # 27 | # coreos-vagrant is configured through a series of configuration 28 | # options (global ruby variables) which are detailed below. To modify 29 | # these options, first copy this file to "config.rb". Then simply 30 | # uncomment the necessary lines, leaving the $, and replace everything 31 | # after the equals sign.. 32 | 33 | # Size of the CoreOS cluster created by Vagrant 34 | $num_instances=3 35 | 36 | # Official CoreOS channel from which updates should be downloaded 37 | $update_channel="stable" 38 | 39 | # Log the serial consoles of CoreOS VMs to log/ 40 | # Enable by setting value to true, disable with false 41 | # WARNING: Serial logging is known to result in extremely high CPU usage with 42 | # VirtualBox, so should only be used in debugging situations 43 | #$enable_serial_logging=false 44 | 45 | # Enable port forwarding of Docker TCP socket 46 | # Set to the TCP port you want exposed on the *host* machine, default is 2375 47 | # If 2375 is used, Vagrant will auto-increment (e.g. in the case of $num_instances > 1) 48 | # You can then use the docker tool locally by setting the following env var: 49 | # export DOCKER_HOST='tcp://127.0.0.1:2375' 50 | #$expose_docker_tcp=2375 51 | 52 | # Setting for VirtualBox VMs 53 | #$vb_gui = false 54 | #$vb_memory = 1024 55 | #$vb_cpus = 1 56 | -------------------------------------------------------------------------------- /coreos/user-data.yml.erb: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | coreos: 4 | update: 5 | group: stable 6 | reboot-strategy: off 7 | units: 8 | - name: settimezone.service 9 | command: start 10 | content: | 11 | [Unit] 12 | Description=Set the timezone 13 | 14 | [Service] 15 | ExecStart=/usr/bin/timedatectl set-timezone <%= ENV["TIMEZONE"] %> 16 | RemainAfterExit=yes 17 | Type=oneshot 18 | - name: install-docker-compose.service 19 | command: start 20 | content: | 21 | [Unit] 22 | Description=Set the timezone 23 | 24 | [Service] 25 | ExecStartPre=/usr/bin/mkdir -p /opt/bin 26 | ExecStart=/usr/bin/wget https://github.com/docker/compose/releases/download/<%= ENV["COMPOSE_VERSION"] %>/docker-compose-Linux-x86_64 -O /opt/bin/compose 27 | ExecStartPost=/usr/bin/chown root:root /opt/bin/compose 28 | ExecStartPost=/usr/bin/chmod +x /opt/bin/compose 29 | RemainAfterExit=yes 30 | Type=oneshot 31 | - name: docker-tcp.socket 32 | command: start 33 | enable: true 34 | content: | 35 | [Unit] 36 | Description=Docker Socket for the API 37 | 38 | [Socket] 39 | ListenStream=2375 40 | Service=docker.service 41 | BindIPv6Only=both 42 | 43 | [Install] 44 | WantedBy=sockets.target 45 | users: 46 | - name: cap 47 | ssh-authorized-keys: 48 | - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBEQq/D8lfTVIeM2cSZeUUe/xt9fqHpQS2rgnp2MLVXygxok85F88+/rhTAtuaNYvhrfV0QEljo4py/cbON/ryfniHGApEumT+eVZeJWwgKaQ2dSfqypXjouJ5JPIRHQLqbouGPw+ohFERetMLGu290qN00XzUrVnW4ERFTrMVkikyFN668zViuGc+KaOO9rXFygIEPule2icA2G+u8f9a/ByY6nxi92XQHDdXVMN1OK0u7QtJ+/QrFZx3TgdnHnVhrvCQqANlOVJ7xaqWyq4AwFNPcGfBSUMPcHh7zwyKXT/ifBFuCStVavnCplyqxSbgfqQbY0SRZCKWdRXi/58N seigo@rb9.local 49 | groups: 50 | - sudo 51 | - docker 52 | write_files: 53 | - path: /etc/ssh/sshd_config 54 | permissions: 0600 55 | owner: root:root 56 | content: | 57 | # Use most defaults for sshd configuration. 58 | UsePrivilegeSeparation sandbox 59 | Subsystem sftp internal-sftp 60 | 61 | PermitRootLogin no 62 | PasswordAuthentication no 63 | ChallengeResponseAuthentication no 64 | - path: /etc/ntp.conf 65 | content: | 66 | # Common pool 67 | server 0.pool.ntp.org 68 | server 1.pool.ntp.org 69 | server 2.pool.ntp.org 70 | server 3.pool.ntp.org 71 | 72 | # - Allow only time queries, at a limited rate. 73 | # - Allow all local queries (IPv4, IPv6) 74 | restrict default nomodify nopeer noquery limited kod 75 | restrict 127.0.0.1 76 | restrict [::1] 77 | - path: /opt/bin/cap 78 | permissions: 0755 79 | owner: core:core 80 | content: | 81 | #!/bin/bash 82 | # 83 | # Usage: script/cap -T 84 | # 85 | 86 | /home/core/docker-example-capistrano/script/run cap $@ 87 | -------------------------------------------------------------------------------- /script/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spesnova/docker-example-capistrano/cf03c22003c52207518bd8dfd5f23bb89d699c69/script/.gitkeep -------------------------------------------------------------------------------- /script/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Usage: script/build 4 | # Description: build helper 5 | 6 | set -e 7 | 8 | echo "==> Building image..." 9 | docker build -t=quay.io/spesnova/docker-example-capistrano . 10 | -------------------------------------------------------------------------------- /script/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Usage: 4 | # script/run bash 5 | # script/run cap -T 6 | # 7 | 8 | set -e 9 | 10 | docker run \ 11 | --rm \ 12 | -it \ 13 | --name capistrano.`date +%s` \ 14 | -v /home/core/docker-example-capistrano/capistrano:/capistrano \ 15 | --net=host \ 16 | quay.io/spesnova/docker-example-capistrano \ 17 | $@ 18 | -------------------------------------------------------------------------------- /script/run-postgres: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Usage: script/run-postgres 4 | # Descriptin: run PostgreSQL container 5 | # 6 | 7 | set -e 8 | 9 | docker kill postgres > /dev/null 2>&1 || true 10 | docker rm postgres > /dev/null 2>&1 || true 11 | 12 | docker run \ 13 | -d \ 14 | --name postgres \ 15 | -e POSTGRES_USER="hello" \ 16 | -e POSTGRES_PASSWORD="world" \ 17 | -p 5432:5432 \ 18 | postgres:9.4.0 19 | -------------------------------------------------------------------------------- /script/run-rails: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Usage: script/run 4 | # Descriptin: run Rails container 5 | # 6 | 7 | set -e 8 | 9 | IMAGE="quay.io/spesnova/docker-example-rails" 10 | 11 | docker kill docker-example-rails > /dev/null 2>&1 || true 12 | docker rm docker-example-rails > /dev/null 2>&1 || true 13 | 14 | docker run \ 15 | -it \ 16 | --rm \ 17 | --name docker-example-rails \ 18 | -e DATABASE_HOST="$(docker inspect -f="{{ .NetworkSettings.IPAddress }}" postgres)" \ 19 | -e DATABASE_PORT="5432" \ 20 | -e DATABASE_USER="hello" \ 21 | -e DATABASE_PASSWORD="world" \ 22 | -e SECRET_KEY_BASE="450a851180c712e6a7ba6f4ab4a9624caddfc02d842eef3315cc47f9b0a16ef3cb5e5b68184d998604076a05d32d108b465f7bfe23623222690be720c7bfd39c" \ 23 | -e RACK_ENV=production \ 24 | -e RAILS_SERVE_STATIC_FILES=true \ 25 | -p 80:3000 \ 26 | -v /app \ 27 | "${IMAGE}" \ 28 | $@ 29 | --------------------------------------------------------------------------------