deployku 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dfe59e855f60f211b591d800f31a729fe253735e
4
+ data.tar.gz: 0c413f1ebc00d71e88b727a1929d1eb39d6dea84
5
+ SHA512:
6
+ metadata.gz: ee135823a37281fc4cd377ded1c5bb522d9c295203d8e02237505f4f89c3b93b4bba685d7997c59b57e28b2654fad615b68ef8636baca70ddcff7361b32215db
7
+ data.tar.gz: 5c38b6c78b376b3e093dc06273988c66e0f778e487e8516ca43a962dee7b7bed1db9a01ad73d705079a24f2694d115fb9e3e948e90348cad00a413f27a1f72d2
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (C) 2015 Petr Kovář <pejuko@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # DEPLOYKU
2
+
3
+ Deploy applications using git with zero down time. Inspired by dokku but should be distribution independent.
4
+
5
+ ## Instalation instructions
6
+
7
+ ### Required packages
8
+
9
+ * docker or lxc (lxc not implemented yet)
10
+ * ruby with rubygems (system wide)
11
+ * postgresql client (psql command)
12
+ * nginx (server)
13
+ * sshd (server)
14
+ * git
15
+
16
+ ### Installation
17
+
18
+ ```bash
19
+ gem install deployku
20
+ ```
21
+
22
+ ### System configuration
23
+
24
+ Add new user 'deployku' and add him to docker group
25
+ ```bash
26
+ useradd -m deployku -G docker
27
+ ```
28
+
29
+ Configure nginx to load nginx.conf files from ~deployku/*/nginx.conf. Eg.:
30
+ ```
31
+ http {
32
+ ...
33
+ include /home/deployku/*/nginx.conf;
34
+ }
35
+ ```
36
+
37
+ To allow user deployku to reload nginx configuration via sudo add following line to /etc/sudoers
38
+ ```bash
39
+ %deployku ALL=(ALL) NOPASSWD:/usr/bin/nginx -s reload
40
+ ```
41
+
42
+ Store path to deployku into ~deployku/.sshcommand:
43
+ ```bash
44
+ which deployku > /home/deployku/.sshcommand
45
+ ```
46
+
47
+ As user deployku add first ssh key. The first user will be manager and will have admin privileges to all repositories.
48
+ The command reads one line from stdin and expects the line to be a public ssh key. So you can do something like this:
49
+ ```bash
50
+ su - deployku
51
+ cat id_rsa.pub | deployku access:add peter
52
+ ```
53
+
54
+ User peter is now deployku administrator and can do everything. Please notice that this works only for first time.
55
+ Adding another deployku users can be done over ssh by deployku administrator. So user peter now can add another administrator:
56
+ ```bash
57
+ cat id_rsa2.pub | ssh deployku@localhost access:add thomas
58
+ ssh deployku@localhost access:acl:system_set thomas admin
59
+ ```
60
+
61
+ For more information run command like this:
62
+ ```bash
63
+ ssh deployku@localhost help
64
+ ```
65
+
66
+ Replace 'localhost' with your domain.
67
+
68
+ ## Custom files
69
+
70
+ ### Custom start script
71
+
72
+ After the container is started the `/start` script is executed. The `/start` script is generated by the application plugin.
73
+ If you wish to use your own start script just create and commit your own start script. The custom start script has to be
74
+ in your application root and has to expect that the application is in `/app` directory.
75
+
76
+ Example of custom start script:
77
+ ```bash
78
+ #!/usr/bin/env bash
79
+
80
+ source /usr/local/rvm/scripts/rvm
81
+
82
+ cd /app
83
+
84
+ export RAILS_ENV=production
85
+
86
+ bundle exec rake db:migrate RAILS_ENV=production
87
+ bundle exec rake assets:precompile RAILS_ENV=production
88
+
89
+ mkdir -p tmp/pids
90
+ bundle exec sidekiq -c 2 -e production -d -L log/sidekiq.log -P tmp/pids/sidekiq.pid
91
+ bundle exec puma -p 3000 -e production --pidfile tmp/pids/puma.pid
92
+ ```
93
+
94
+ ### Custom Dockerfile
95
+
96
+ You may prepare your own image or for some other reasons you may want to create custom containers. Just create Dockerfile in your
97
+ application root and commit it. When you push to deployku repository it will be used.
98
+
99
+ Example of custom Dockerfile:
100
+ ```
101
+ FROM pejuko/rvm-base
102
+
103
+ ENV DEBIAN_FRONTEND noninteractive
104
+
105
+ RUN apt-get update
106
+
107
+ RUN /bin/bash -l -c 'rvm install 2.2.3 && rvm use 2.2.3 --default'
108
+ RUN /bin/bash -l -c 'rvm rubygems current'
109
+ RUN /bin/bash -l -c 'gem install bundler'
110
+
111
+ RUN /bin/bash -l -c 'rvm cleanup all'
112
+
113
+ RUN apt-get install -y libpq-dev
114
+
115
+ RUN apt-get -y autoclean
116
+ RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
117
+
118
+ EXPOSE 3000
119
+ CMD []
120
+ ENTRYPOINT ["/start"]
121
+
122
+ ADD start /start
123
+
124
+ ADD app /app
125
+ RUN /bin/bash -l -c 'cd app && RAILS_ENV=production bundle install --without development test'
126
+ ```
127
+
128
+ ## Supported applications
129
+
130
+ * Ruby on Rails
131
+
132
+ ## Examples
133
+
134
+ ### Create new project and assign commit rights to jane
135
+
136
+ ```bash
137
+ ssh deployku@localhost app:create myapp
138
+ cat jane.pub | ssh deployku@localhost access:add jane
139
+ ssh deployku@localhost access:acl:set myapp jane commit
140
+ ```
141
+
142
+ Jane now can deploy with git.
143
+
144
+ ### Create and start new PostgreSQL server
145
+
146
+ ```bash
147
+ ssh deployku@localhost postgres:create dbserver
148
+ ssh deployku@localhost postgres:start dbserver
149
+ ```
150
+
151
+ ### Create and configure new Rails application
152
+
153
+ Create new repository on deployku server (replace localhost with name of your server)
154
+ ```bash
155
+ ssh deployku@localhost app:create myapp
156
+ ```
157
+
158
+ Create new database on running database server
159
+ ```bash
160
+ ssh deployku@localhost postgres:db:create dbserver myapp-db
161
+ ```
162
+
163
+ Link created database to our application
164
+ ```bash
165
+ ssh deployku@localhost postgres:db:link dbserver myapp-db myapp
166
+ ```
167
+
168
+ To say that we want to install postgresql dev tools in our container you can create file `deployku.yml` in your
169
+ application directory:
170
+ ```yaml
171
+ packages: ['libpq-dev']
172
+ ```
173
+
174
+ OR you can setup this in the repository with:
175
+ ```bash
176
+ ssh deployku@localhost app:config:add_package libpq-dev
177
+ ```
178
+
179
+ Configure our server domains
180
+ ```bash
181
+ ssh deployku@localhost app:config:add_domain myapp myapp.com
182
+ ssh deployku@localhost app:config:add_domain myapp www.myapp.com
183
+ ```
184
+
185
+ Enable nginx server
186
+ ```bash
187
+ ssh deployku@localhost nginx:enable myapp
188
+ ```
189
+
190
+ Check our configuration
191
+ ```bash
192
+ ssh deployku@localhost app:config:show myapp
193
+ ```
194
+
195
+ Setup application environment like SECRET_KEY_BASE for rails app
196
+ ```bash
197
+ ssh deployku@localhost app:config:set myapp SECRET_KEY_BASE somesecretkey
198
+ ```
199
+
200
+ Setup our deployku repository as remote branch
201
+ ```bash
202
+ git remote add deployku deployku@localhost:myapp
203
+ ```
204
+
205
+ Deploy.
206
+ ```bash
207
+ git push deployku master
208
+ ```
209
+
210
+ ### Connect to database
211
+ Use ssh with `-t` option.
212
+ ```bash
213
+ ssh -t deployku@localhost postgres:db:connect dbserver myapp-db
214
+ ```
215
+
216
+ ### Exec command in container environment
217
+ Following will run bash inside container. Use ssh with `-t` option.
218
+ ```bash
219
+ ssh -t deployku@localhost app:run myapp bash
220
+ ```
221
+
222
+ And then you can enter your app directory:
223
+ ```bash
224
+ cd app
225
+ ```
226
+
227
+ And run eg. rails console:
228
+ ```bash
229
+ rails c
230
+ ```
231
+
232
+ ## ACL: rights
233
+ - admin
234
+ - commit
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ # vi: fenc=utf-8:expandtab:ts=2:sw=2:sts=2
3
+ #
4
+ # @author: Petr Kovar <pejuko@gmail.com>
5
+
6
+ require 'rubygems/package_task'
7
+ require 'rake/clean'
8
+
9
+ CLEAN << "pkg"
10
+
11
+ task :default => [:gem]
12
+
13
+ Gem::PackageTask.new(eval(File.read("deployku.gemspec"))) {|pkg|}
14
+
data/bin/deployku ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), "../lib"))
4
+
5
+ require 'deployku'
6
+
7
+ cmd = ARGV.shift
8
+
9
+ def print_help
10
+ puts <<EOF
11
+
12
+ deployku <command> [command-options]
13
+
14
+ Commands:
15
+ #{Deployku::Plugin.help}
16
+ EOF
17
+ end
18
+
19
+ unless cmd
20
+ print_help
21
+ exit 1
22
+ end
23
+
24
+ Deployku::Config.load
25
+
26
+ case cmd
27
+ when 'help'
28
+ print_help
29
+ exit 0
30
+
31
+ when /^([^:]+):(.*)$/
32
+ plugin = Deployku::Plugin.find_plugin($1)
33
+ unless plugin
34
+ print_help
35
+ exit 1
36
+ end
37
+ plugin.run($2, ARGV)
38
+
39
+ when 'git-receive-pack'
40
+ Deployku::GitPlugin.instance.receive_pack(ARGV.shift)
41
+
42
+ else
43
+ print_help
44
+ exit 1
45
+ end
data/deployku.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- coding: utf-8 -*-
2
+ # vi: fenc=utf-8:expandtab:ts=2:sw=2:sts=2
3
+ #
4
+ # @author: Petr Kovar <pejuko@gmail.com>
5
+
6
+ require 'rubygems'
7
+ require 'find'
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.platform = Gem::Platform::RUBY
11
+ s.summary = "Deploy applications using git with zero down time"
12
+ s.homepage = "http://github.com/deployku/deployku"
13
+ s.email = "pejuko@gmail.com"
14
+ s.authors = ["Petr Kovář"]
15
+ s.name = 'deployku'
16
+ s.version = '0.0.1'
17
+ s.date = Time.now.strftime("%Y-%m-%d")
18
+ s.require_path = 'lib'
19
+ s.files = ["bin/deployku", "README.md", "deployku.gemspec", "Rakefile", "LICENSE"]
20
+ s.files += Dir["lib/**/*.rb"]
21
+ s.executables = ["deployku"]
22
+ end
23
+
@@ -0,0 +1,92 @@
1
+ require 'yaml'
2
+
3
+ module Deployku
4
+ class Config
5
+ # TODO: read variables from config file
6
+
7
+ @config = nil
8
+
9
+ HOME = File::expand_path('~deployku')
10
+ FROM = 'pejuko/rvm-base'
11
+ PACKAGES = ['git']
12
+ DEFAULT_ENGINE = 'docker'
13
+ DEFAULT_PORT = 80
14
+
15
+ class << self
16
+ def home
17
+ HOME
18
+ end
19
+
20
+ def engine
21
+ (@config && @config['engine']) ? @config['engine'] : DEFAULT_ENGINE
22
+ end
23
+
24
+ def from
25
+ (@config && @config['from']) ? @config['from'] : FROM
26
+ end
27
+
28
+ def packages
29
+ (@config && @config['packages']) ? @config['packages'] : PACKAGES
30
+ end
31
+
32
+ def port
33
+ (@config && @config['port']) ? @config['port'] : DEFAULT_PORT
34
+ end
35
+
36
+ def method_missing(method, *args)
37
+ return nil unless @config
38
+ return @config[method.to_s]
39
+ end
40
+
41
+ def merge!(opts)
42
+ unless @config
43
+ @config = {
44
+ 'from' => FROM,
45
+ 'packages' => PACKAGES,
46
+ 'engine' => DEFAULT_ENGINE
47
+ }
48
+ end
49
+ deep_merge!(@config, opts)
50
+ end
51
+
52
+ def deep_merge!(hash1, hash2)
53
+ hash2.each do |key, value|
54
+ k = key.to_s
55
+ unless hash1[k]
56
+ hash1[k] = value
57
+ else
58
+ if hash1[k].kind_of?(Hash)
59
+ deep_merge!(hash1[k], value)
60
+ elsif hash1[k].kind_of?(Array)
61
+ hash1[k] = hash1[k] + value
62
+ else
63
+ hash1[k] = value
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ def set_opts(key, opts)
70
+ @config[key.to_s] = opts[key.to_s] if opts[key.to_s]
71
+ end
72
+
73
+ def load(path=File.join(HOME, '.deployku.yaml'))
74
+ if File.exists?(path)
75
+ deployku_config = YAML.load_file(path)
76
+ Deployku::Config.merge!(deployku_config)
77
+ true
78
+ else
79
+ false
80
+ end
81
+ end
82
+
83
+ def save(path=File.join(HOME, '.deployku.yaml'))
84
+ if @config
85
+ File.open(path, 'w') do |f|
86
+ f << @config.to_yaml
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,75 @@
1
+ require 'fileutils'
2
+ require 'yaml'
3
+
4
+ module Deployku::Configurable
5
+ attr_reader :config
6
+
7
+ def config_show(app_name)
8
+ app_config_path = config_path(app_name)
9
+ puts File.read(app_config_path) if File.exists?(app_config_path)
10
+ end
11
+
12
+ def config_set(app_name, var, value)
13
+ config_load(app_name)
14
+ @config['env'][var.to_s] = value
15
+ config_save(app_name)
16
+ end
17
+
18
+ def config_unset(app_name, var)
19
+ config_load(app_name)
20
+ @config['env'].delete(var.to_s)
21
+ config_save(app_name)
22
+ end
23
+
24
+ def config_set_from(app_name, value)
25
+ config_load(app_name)
26
+ @config['from'] = value
27
+ config_save(app_name)
28
+ end
29
+
30
+ def config_unset_from(app_name)
31
+ config_load(app_name)
32
+ @config.delete('from')
33
+ config_save(app_name)
34
+ end
35
+
36
+ def config_set_engine(app_name, value)
37
+ config_load(app_name)
38
+ @config['engine'] = value
39
+ config_save(app_name)
40
+ end
41
+
42
+ def config_unset_engine(app_name)
43
+ config_load(app_name)
44
+ @config.delete('engine')
45
+ config_save(app_name)
46
+ end
47
+
48
+ def config_set_port(app_name, value)
49
+ config_load(app_name)
50
+ @config['port'] = value
51
+ config_save(app_name)
52
+ end
53
+
54
+ def config_unset_port(app_name)
55
+ config_load(app_name)
56
+ @config.delete('port')
57
+ config_save(app_name)
58
+ end
59
+
60
+ def config_load(app_name)
61
+ app_config_path = config_path(app_name)
62
+ @config.merge!(YAML.load_file(app_config_path)) if File.exists?(app_config_path)
63
+ end
64
+
65
+ def config_save(app_name)
66
+ app_config_path = config_path(app_name)
67
+ File.open(app_config_path, 'w') do |f|
68
+ f << @config.to_yaml
69
+ end
70
+ end
71
+
72
+ def config_path(app_name)
73
+ File.join(dir(app_name), 'DEPLOYKU_CONFIG.yml')
74
+ end
75
+ end
@@ -0,0 +1,82 @@
1
+ module Deployku::Containerable
2
+ def start(app_name)
3
+ Deployku::Config.load(config_path(app_name))
4
+ app_name = Deployku.sanitize_app_name(app_name)
5
+ app_hash = Deployku::Engine.start(app_name, dir(app_name))
6
+ exit 1 if $?.nil? || $?.exitstatus != 0
7
+ set_container_id(app_name, app_hash)
8
+ puts "Container #{app_hash} started."
9
+ end
10
+
11
+ def run(app_name, *cmd)
12
+ Deployku::Config.load(config_path(app_name))
13
+ app_name = Deployku.sanitize_app_name(app_name)
14
+ Deployku::Engine.run(app_name, dir(app_name), *cmd)
15
+ exit 1 if $?.nil? || $?.exitstatus != 0
16
+ end
17
+
18
+ def stop(app_name, cid: nil)
19
+ Deployku::Config.load(config_path(app_name))
20
+ app_hash = cid ? cid : get_container_id(app_name)
21
+ if app_hash
22
+ Deployku::Engine.stop(app_hash)
23
+ end
24
+ end
25
+
26
+ def restart(app_name)
27
+ old_cid = get_container_id(app_name)
28
+ if start(app_name)
29
+ # stops old application only if new instance was spawn
30
+ stop(app_name, cid: old_cid)
31
+ end
32
+ end
33
+
34
+ def logs(app_name)
35
+ Deployku::Config.load(config_path(app_name))
36
+ app_hash = get_container_id(app_name)
37
+ Deployku::Engine.logs(app_hash)
38
+ end
39
+
40
+
41
+ def container_id_path(app_name)
42
+ File.join(dir(app_name), 'CONTAINER_ID')
43
+ end
44
+
45
+ def get_container_id(app_name)
46
+ container_hash_path = container_id_path(app_name)
47
+ if File.exists?(container_hash_path)
48
+ File.read(container_hash_path)
49
+ else
50
+ nil
51
+ end
52
+ end
53
+
54
+ def set_container_id(app_name, hash)
55
+ container_hash_path = container_id_path(app_name)
56
+ File.open(container_hash_path, 'w') do |f|
57
+ f << hash
58
+ end
59
+ end
60
+
61
+ def status(app_name)
62
+ s = get_status(app_name)
63
+ if s == nil
64
+ puts 'Container does not exist.'
65
+ else
66
+ if s == true
67
+ puts 'Container is running.'
68
+ else
69
+ puts 'Container is not running.'
70
+ end
71
+ end
72
+ end
73
+
74
+ def get_status(app_name)
75
+ cid = get_container_id(app_name)
76
+ if cid
77
+ Deployku::Engine.running?(cid)
78
+ else
79
+ nil
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,55 @@
1
+ module Deployku::Engine
2
+ class MissingException < Exception
3
+ end
4
+
5
+ def self.find_engine(name)
6
+ plugin_name = "Deployku::#{name.capitalize}Engine"
7
+ Deployku::Plugin.plugins.each do |plugin|
8
+ return plugin if plugin.name == plugin_name
9
+ end
10
+ nil
11
+ end
12
+
13
+ def self.engines
14
+ engs = []
15
+ Deployku::Plugin.plugins.each do |plugin|
16
+ engs << plugin if plugin.name =~ /^Deployku::.*?Engine$/
17
+ end
18
+ engs
19
+ end
20
+
21
+ def self.method_missing(method, *args)
22
+ engine = find_engine(Deployku::Config.engine)
23
+ raise MissingException.new("no engine '#{Deployku::Config.engine}' found") unless engine
24
+ eng = engine.new
25
+ eng.send(method, *args)
26
+ end
27
+
28
+ def start(app_name, app_dir)
29
+ puts 'not implemented'
30
+ end
31
+
32
+ def run(app_name, app_dir, *cmd)
33
+ puts 'not implemented'
34
+ end
35
+
36
+ def stop(app_hash)
37
+ puts 'not implemented'
38
+ end
39
+
40
+ def logs(app_hash)
41
+ puts 'not implemented'
42
+ end
43
+
44
+ def rebuild(app_name, dir)
45
+ puts 'not implemented'
46
+ end
47
+
48
+ def running?(app_hash)
49
+ puts 'not implemented'
50
+ end
51
+
52
+ def ip(app_hash)
53
+ puts 'not implemented'
54
+ end
55
+ end
@@ -0,0 +1,7 @@
1
+ module Deployku
2
+ class << self
3
+ def sanitize_app_name(app_name)
4
+ app_name.gsub(%r{^\.+}, '').gsub(%r{\.+$}, '').gsub(%r{\.\./}, '').gsub(%r{^/+}, '').gsub(%r{/+$}, '').gsub(%r{/+}, '-').gsub(%r{\s+}, '_').gsub(%r{[^a-zA-Z0-9_\-\.]}, '')
5
+ end
6
+ end
7
+ end