terra_boi 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +231 -0
- data/Rakefile +27 -0
- data/lib/generators/extensions.rb +29 -0
- data/lib/generators/terra_boi/boilerplate_generator.rb +35 -0
- data/lib/generators/terra_boi/data_generator.rb +38 -0
- data/lib/generators/terra_boi/dockerfile_generator.rb +28 -0
- data/lib/generators/terra_boi/host_initializer_generator.rb +27 -0
- data/lib/generators/terra_boi/packer_generator.rb +26 -0
- data/lib/generators/terra_boi/state_generator.rb +25 -0
- data/lib/generators/terra_boi/templates/Dockerfile.erb +39 -0
- data/lib/generators/terra_boi/templates/data_main.erb +31 -0
- data/lib/generators/terra_boi/templates/data_output.erb +19 -0
- data/lib/generators/terra_boi/templates/host_initializer.erb +4 -0
- data/lib/generators/terra_boi/templates/packer_ami_build.erb +22 -0
- data/lib/generators/terra_boi/templates/packer_application.erb +41 -0
- data/lib/generators/terra_boi/templates/state_main.erb +10 -0
- data/lib/generators/terra_boi/templates/web_servers_main.erb +30 -0
- data/lib/generators/terra_boi/templates/web_servers_output.erb +14 -0
- data/lib/generators/terra_boi/web_servers_generator.rb +39 -0
- data/lib/tasks/terra_boi_tasks.rake +4 -0
- data/lib/terra_boi/railtie.rb +4 -0
- data/lib/terra_boi/version.rb +3 -0
- data/lib/terra_boi.rb +5 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2e07549528cc229186be4d0024ebff13717dffe397b4da9611c2bc9e6601a21a
|
4
|
+
data.tar.gz: e3ea9d7cae1344535ecbcf33a7a22b24679e8b668980f8b4bd0e7d27eabd5551
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9722cee6653bf1790d6ca23f957d32b42098feae3783c7b95cf0337250b6c8dcc7ea43c0fdc66bceece9aaa65ea49fdaf63d57e451c450ebc5bce110fdb581a6
|
7
|
+
data.tar.gz: 3ce672b519f3d22ec25fc71d89b149f8974e8aadc541c7d409343f0fabad56f0866a6cea04cd96050a86225dd045d787a79b0a42e6ca2127ffe8a8a69692b9fc
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2019
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
# TerraBoi
|
2
|
+
|
3
|
+
This gem was created to get rails applications deployed into production as quickly and easily as possible.
|
4
|
+
|
5
|
+
**Raison d'etre**: creating basic infrastructure to house production SaaS applications on AWS is tedious and boring. It's often a similar process every time, and every time it sucks.
|
6
|
+
|
7
|
+
List of items created by this gem's generators:
|
8
|
+
- Dockerfile
|
9
|
+
- Rails initializer file (for setting up config.hosts)
|
10
|
+
- Packer repository (for creating AMIs)
|
11
|
+
- Terraform repository (for creating infrastructure as code to immediately deploy staging / prod infrastructure as well as rolling out application updates)
|
12
|
+
|
13
|
+
**Note**: generated Terraform files create / support remote state locking, load-balancing, auto-scaling, zero-downtime web app deployments, DBs, and S3 buckets.
|
14
|
+
|
15
|
+
**Note**: after infrastructure files are generated, you will be ready to deploy your application to staging / production on AWS. If you have more advanced infrastructure needs (e.g. Redis / Solr instances), you may add to the generated Terraform files to support this.
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
## Pre-requisites
|
20
|
+
|
21
|
+
* [Terraform](https://www.terraform.io/) installed on your computer
|
22
|
+
* [Packer](https://www.packer.io/downloads.html) installed on your computer
|
23
|
+
* [Amazon Web Services (AWS) account](http://aws.amazon.com/)
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
## Installation
|
28
|
+
|
29
|
+
**Note**: below installation steps should be completed in order.
|
30
|
+
|
31
|
+
### Installation - gem
|
32
|
+
|
33
|
+
Add this line to your (Rails) application's Gemfile:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
gem 'terra_boi'
|
37
|
+
```
|
38
|
+
|
39
|
+
And then execute:
|
40
|
+
|
41
|
+
```bash
|
42
|
+
$ bundle
|
43
|
+
```
|
44
|
+
|
45
|
+
### Installation - AWS access
|
46
|
+
|
47
|
+
Set up your [AWS access / secret access
|
48
|
+
keys](http://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys) in `~/.zprofile` (or equivalent file for your shell if not using .zsh) as environment variables:
|
49
|
+
|
50
|
+
```
|
51
|
+
export AWS_ACCESS_KEY_ID=your_access_key_id
|
52
|
+
export AWS_SECRET_ACCESS_KEY=your_secret_access_key
|
53
|
+
```
|
54
|
+
|
55
|
+
Then run `source ~/.zprofile` (or equivalent command for your shell if not using .zsh)
|
56
|
+
|
57
|
+
### Installation - generate infrastructure code
|
58
|
+
|
59
|
+
To generate boilerplate infrastructure code (config.host initializer filer, Dockerfile, Packer repository, and terraform repository):
|
60
|
+
|
61
|
+
`rails generate terra_boi:boilerplate --domain_name DOMAIN.COM --ruby_version 2.5.1`
|
62
|
+
|
63
|
+
### Installation - Packer (creating web server AMIs)
|
64
|
+
|
65
|
+
**A. Create private DockerHub repository**
|
66
|
+
|
67
|
+
Create private DockerHub repository for your rails application (if possible, use the exact same name as your rails application).
|
68
|
+
|
69
|
+
**Note**: packer generator will assume your DockerHub repository has the same name as your rails application folder. If this isn't true, update generated Packer `ami_build.json` file after it is generated.
|
70
|
+
|
71
|
+
**B. Setup DockerHub access:**
|
72
|
+
|
73
|
+
Add DockerHub username and access key to `~/.zprofile` (or equivalent file for your shell if not using .zsh) as environment variables (if your image is in a private repository):
|
74
|
+
|
75
|
+
```
|
76
|
+
DOCKERHUB_USERNAME=myname
|
77
|
+
DOCKERHUB_ACCESS_TOKEN=myAccessToken
|
78
|
+
export DOCKERHUB_USERNAME DOCKERHUB_ACCESS_TOKEN
|
79
|
+
```
|
80
|
+
|
81
|
+
Then run `source ~/.zprofile` (or equivalent command for your shell if not using .zsh)
|
82
|
+
|
83
|
+
**Note**: DockerHub access key can be found at https://hub.docker.com/settings/security
|
84
|
+
|
85
|
+
### Installation - Terraform (deploying DBs + web server AMIs)
|
86
|
+
|
87
|
+
**A. Set up remote state:**
|
88
|
+
|
89
|
+
`cd terraform/state`
|
90
|
+
|
91
|
+
Run `terraform init` and then `terraform apply` to set up s3 bucket and dynamoDB for remote state and locking (this will work for both prod and staging).
|
92
|
+
|
93
|
+
**B. Set up DB / S3:**
|
94
|
+
|
95
|
+
`cd terraform/[ENV]/data`
|
96
|
+
|
97
|
+
Set terraform data-related environment variables in .zprofile (or your respective shell dotfile)
|
98
|
+
|
99
|
+
```
|
100
|
+
TF_VAR_db_password=your_password
|
101
|
+
TF_VAR_db_username=your_username
|
102
|
+
```
|
103
|
+
|
104
|
+
To deploy infrastructure to AWS:
|
105
|
+
|
106
|
+
```
|
107
|
+
terraform init # IF NOT ALREADY RUN
|
108
|
+
terraform apply
|
109
|
+
```
|
110
|
+
|
111
|
+
**C. Set up web servers:**
|
112
|
+
|
113
|
+
`cd terraform/[ENV]/web_servers`
|
114
|
+
|
115
|
+
To deploy infrastructure to AWS:
|
116
|
+
|
117
|
+
```
|
118
|
+
terraform init # IF NOT ALREADY RUN
|
119
|
+
terraform apply
|
120
|
+
```
|
121
|
+
|
122
|
+
While aws_acm_certificate_validation.cert is creating (it will hang if you don't add CNAME verification record in ACM):
|
123
|
+
|
124
|
+
i. Log into AWS console, go to certificate management, and add the created CNAME record specified to the DNS configuration for your domain
|
125
|
+
ii. Redirect domain name to Application load balancer:
|
126
|
+
- Go to your domain registrar of choice
|
127
|
+
- Create alias record that points to the dns name of the application load balancer (use subdomain in alias record like STAGING.example.com for staging)
|
128
|
+
- Create URL redirect record for prod (redirect www.site.com to site.com)
|
129
|
+
|
130
|
+
After these changes propogate (should take about an hour or two locally), your webservers should be set up, https should be working, and you should be good to go!
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
## Usage
|
135
|
+
|
136
|
+
**Note**: below usage steps should be completed in order
|
137
|
+
|
138
|
+
### Usage - Packer (creating web server AMIs)
|
139
|
+
|
140
|
+
**A. Push latest application image to DockerHub**
|
141
|
+
|
142
|
+
You can automatically trigger DockerHub image builds when new code is pushed to a repository's master branch using DockerHub's free Github integration.
|
143
|
+
|
144
|
+
Otherwise, `docker push [DOCKER_USERNAME]/[APPLICATION_NAME]:latest`. Make sure you are pushing to a private repository.
|
145
|
+
|
146
|
+
**B. Create Packer AMI:**
|
147
|
+
|
148
|
+
```
|
149
|
+
cd packer
|
150
|
+
|
151
|
+
packer build -var DOCKERHUB_ACCESS_TOKEN=$DOCKERHUB_ACCESS_TOKEN -var DOCKERHUB_USERNAME=$DOCKERHUB_USERNAME application.json
|
152
|
+
```
|
153
|
+
|
154
|
+
**C. Clean up:**
|
155
|
+
|
156
|
+
Every so often you'll want to remove old AMIs created by Packer (unless you want to be charged a couple cents a month).
|
157
|
+
|
158
|
+
To remove them, deregister them on the [AWS AMI management page](https://us-east-2.console.aws.amazon.com/ec2/v2/home?region=us-east-2#Images:sort=name), then delete the associated snapshot on the [AWS snapshot management page](https://us-east-2.console.aws.amazon.com/ec2/home?region=us-east-2#Snapshots:sort=snapshotId).
|
159
|
+
|
160
|
+
### Usage - Terraform (update web server AMIs)
|
161
|
+
|
162
|
+
**A. Update Terraform web server AMIs:**
|
163
|
+
|
164
|
+
`cd terraform/[ENV]/web_servers`
|
165
|
+
|
166
|
+
To deploy infrastructure to AWS:
|
167
|
+
|
168
|
+
```
|
169
|
+
terraform init # IF NOT ALREADY RUN
|
170
|
+
terraform apply
|
171
|
+
```
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
## Infrastructure created
|
176
|
+
|
177
|
+
The aforementioned generators create a `terraform` directory with `state`, `prod`, and `staging` subdirectories.
|
178
|
+
|
179
|
+
The `state` directory contains an S3 bucket and a DynamoDB table to store and lock state (for both prod and staging).
|
180
|
+
|
181
|
+
The `prod` and `staging` subdirectories contain `data` (DB + S3) and `web_servers` (SSL cert, load balancing, autoscaling, EC2) directories.
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
## Running tests
|
186
|
+
|
187
|
+
From the root directory:
|
188
|
+
|
189
|
+
```
|
190
|
+
rake test
|
191
|
+
```
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
## Other tips
|
196
|
+
|
197
|
+
Clean up terraform infrastructure when no longer planning to use (DANGER FOR PROD, WILL DESTROY INFRASTRUCTURE):
|
198
|
+
|
199
|
+
`terraform destroy`
|
200
|
+
|
201
|
+
**For extra security in staging:** update Terraform web_servers `main.tf` file to only allow ingress web_server connections from your IP / your team's IPs
|
202
|
+
|
203
|
+
|
204
|
+
|
205
|
+
## Contributing
|
206
|
+
|
207
|
+
This gem is currently not actively accepting contributions.
|
208
|
+
|
209
|
+
With that in mind, if you'd like to make a fix / change, please create a pull request (and when I have a moment - probably in a couple weeks time - I'll have a look)!
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
## License
|
214
|
+
|
215
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
216
|
+
|
217
|
+
|
218
|
+
|
219
|
+
## Updating gem version (for maintainers)
|
220
|
+
|
221
|
+
**1. Update version**
|
222
|
+
|
223
|
+
In `lib/terra_boi/version.rb` update version.
|
224
|
+
|
225
|
+
**2. Build gem**
|
226
|
+
|
227
|
+
`gem build terra_boi.gemspec`
|
228
|
+
|
229
|
+
**3. Push gem**
|
230
|
+
|
231
|
+
`gem push terra_boi-X.X.X.gem` (replace X's with version)
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'TerraBoi'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'bundler/gem_tasks'
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
|
21
|
+
Rake::TestTask.new(:test) do |t|
|
22
|
+
t.libs << 'test'
|
23
|
+
t.pattern = 'test/**/*_test.rb'
|
24
|
+
t.verbose = false
|
25
|
+
end
|
26
|
+
|
27
|
+
task default: :test
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module TerraBoi
|
2
|
+
module GeneratorHelpers
|
3
|
+
# https://api.rubyonrails.org/classes/Rails/Generators/NamedBase.html#method-i-application_name
|
4
|
+
def generate_application_name
|
5
|
+
if defined?(Rails) && Rails.application
|
6
|
+
Rails.application.class.name.split("::").first.underscore
|
7
|
+
else
|
8
|
+
"application"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_terraform_files(args)
|
13
|
+
args[:env].each do |env|
|
14
|
+
template(args[:template],
|
15
|
+
"terraform/#{env}/#{args[:file_path]}",
|
16
|
+
{
|
17
|
+
env: env,
|
18
|
+
domain_name: class_options[:domain_name]
|
19
|
+
}
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Rails::Generators::Base
|
27
|
+
include TerraBoi::GeneratorHelpers
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module TerraBoi
|
2
|
+
class BoilerplateGenerator < Rails::Generators::Base
|
3
|
+
attr_accessor :application_name, :class_options
|
4
|
+
class_option :ruby_version, type: :string, default: "2.5.1"
|
5
|
+
class_option :domain_name, type: :string, default: 'example.com'
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
desc (<<-EOF
|
9
|
+
This generator runs the terra_boi web_servers, data,
|
10
|
+
and state generators. It sets up all boilerplate
|
11
|
+
terraform infrastructure needed for a standard web app:
|
12
|
+
DB + load balancer + zero downtime, scalable web app
|
13
|
+
launch config + S3 bucket.
|
14
|
+
|
15
|
+
To execute, run rails generate terra_boi:boilerplate --domain_name example.com
|
16
|
+
EOF
|
17
|
+
.gsub(/[\t]/, '')
|
18
|
+
)
|
19
|
+
|
20
|
+
def init
|
21
|
+
self.class_options = options
|
22
|
+
puts application_name
|
23
|
+
end
|
24
|
+
|
25
|
+
def run_other_generators
|
26
|
+
generate "terra_boi:web_servers --domain_name #{class_options[:domain_name]}"
|
27
|
+
generate "terra_boi:data"
|
28
|
+
generate "terra_boi:state"
|
29
|
+
generate "terra_boi:dockerfile --ruby_version #{class_options[:ruby_version]}"
|
30
|
+
generate "terra_boi:host_initializer --domain_name #{class_options[:domain_name]}"
|
31
|
+
generate "terra_boi:packer"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "generators/extensions"
|
2
|
+
|
3
|
+
module TerraBoi
|
4
|
+
class DataGenerator < Rails::Generators::Base
|
5
|
+
attr_accessor :application_name, :class_options
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
desc (<<-EOF
|
9
|
+
Generate staging and production DB and S3 bucket
|
10
|
+
|
11
|
+
To execute, run rails generate terra_boi:data
|
12
|
+
EOF
|
13
|
+
.gsub(/\t/, '')
|
14
|
+
)
|
15
|
+
|
16
|
+
def init
|
17
|
+
# defined in lib/generators/extensions
|
18
|
+
self.application_name = generate_application_name
|
19
|
+
self.class_options = options
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_main_terraform_file
|
23
|
+
generate_terraform_files({
|
24
|
+
template: 'data_main.erb',
|
25
|
+
file_path: 'data/main.tf',
|
26
|
+
env: ['staging', 'prod']
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_output_terraform_file
|
31
|
+
generate_terraform_files({
|
32
|
+
template: 'data_output.erb',
|
33
|
+
file_path: 'data/output.tf',
|
34
|
+
env: ['staging', 'prod']
|
35
|
+
})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "generators/extensions"
|
2
|
+
|
3
|
+
module TerraBoi
|
4
|
+
class DockerfileGenerator < Rails::Generators::Base
|
5
|
+
attr_accessor :application_name, :class_options
|
6
|
+
class_option :ruby_version, type: :string, default: "2.5.1"
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
8
|
+
|
9
|
+
desc (<<-EOF
|
10
|
+
Generate Dockerfile for rails app
|
11
|
+
|
12
|
+
To execute, run rails generate terra_boi:dockerfile
|
13
|
+
|
14
|
+
Can pass in --ruby_version command line argument. Defaults to 2.5.1.
|
15
|
+
EOF
|
16
|
+
.gsub(/\t/, '')
|
17
|
+
)
|
18
|
+
|
19
|
+
def init
|
20
|
+
self.application_name = generate_application_name
|
21
|
+
self.class_options = options
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_dockerfile
|
25
|
+
template "Dockerfile.erb", "Dockerfile"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "generators/extensions"
|
2
|
+
|
3
|
+
module TerraBoi
|
4
|
+
class HostInitializerGenerator < Rails::Generators::Base
|
5
|
+
attr_accessor :application_name, :class_options
|
6
|
+
class_option :domain_name, type: :string
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
8
|
+
|
9
|
+
desc (<<-EOF
|
10
|
+
Generate host initializer rails file
|
11
|
+
|
12
|
+
To execute, run rails generate terra_boi:host_initializer --domain_name example.com
|
13
|
+
EOF
|
14
|
+
.gsub(/\t/, '')
|
15
|
+
)
|
16
|
+
|
17
|
+
def init
|
18
|
+
# defined in lib/generators/extensions
|
19
|
+
self.application_name = generate_application_name
|
20
|
+
self.class_options = options
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_host_initializer_file
|
24
|
+
template "host_initializer.erb", "config/initializers/hosts.rb"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "generators/extensions"
|
2
|
+
|
3
|
+
module TerraBoi
|
4
|
+
class PackerGenerator < Rails::Generators::Base
|
5
|
+
attr_accessor :application_name
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
desc (<<-EOF
|
9
|
+
Generate packer files for building AWS EC2 AMI
|
10
|
+
|
11
|
+
To execute, run rails generate terra_boi:packer
|
12
|
+
EOF
|
13
|
+
.gsub(/\t/, '')
|
14
|
+
)
|
15
|
+
|
16
|
+
def init
|
17
|
+
# defined in lib/generators/extensions
|
18
|
+
self.application_name = generate_application_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_packer_files
|
22
|
+
template "packer_ami_build.erb", "packer/ami_build.sh"
|
23
|
+
template "packer_application.erb", "packer/application.json"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "generators/extensions"
|
2
|
+
|
3
|
+
module TerraBoi
|
4
|
+
class StateGenerator < Rails::Generators::Base
|
5
|
+
attr_accessor :application_name, :class_options
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
desc (<<-EOF
|
9
|
+
Generate DB and S3 bucket for storing and locking terraform state
|
10
|
+
|
11
|
+
To execute, run rails generate terra_boi:state
|
12
|
+
EOF
|
13
|
+
.gsub(/\t/, '')
|
14
|
+
)
|
15
|
+
|
16
|
+
def init
|
17
|
+
self.application_name = generate_application_name
|
18
|
+
self.class_options = options
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_main_terraform_file
|
22
|
+
template "state_main.erb", "terraform/state/main.tf"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
FROM ruby:<%= class_options[:ruby_version] %>
|
2
|
+
|
3
|
+
# replace shell with bash so we can source files
|
4
|
+
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
|
5
|
+
|
6
|
+
RUN apt-get update -qq && apt-get install -y build-essential
|
7
|
+
|
8
|
+
# # for postgres
|
9
|
+
# RUN apt-get install -y libpq-dev
|
10
|
+
|
11
|
+
# # for nokogiri
|
12
|
+
# RUN apt-get install -y libxml2-dev libxslt1-dev
|
13
|
+
|
14
|
+
# # for capybara-webkit
|
15
|
+
# RUN apt-get install -y libqtwebkit4 libqt4-dev xvfb
|
16
|
+
|
17
|
+
# for a JS runtime
|
18
|
+
RUN curl -sL https://deb.nodesource.com/setup_11.x | bash -
|
19
|
+
RUN apt-get install -y nodejs
|
20
|
+
|
21
|
+
RUN node -v
|
22
|
+
RUN npm -v
|
23
|
+
|
24
|
+
RUN npm install yarn -g
|
25
|
+
|
26
|
+
ENV APP_HOME /<%= application_name %>
|
27
|
+
RUN mkdir $APP_HOME
|
28
|
+
WORKDIR $APP_HOME
|
29
|
+
|
30
|
+
ADD Gemfile* $APP_HOME/
|
31
|
+
RUN bundle install
|
32
|
+
|
33
|
+
ADD . $APP_HOME
|
34
|
+
|
35
|
+
RUN yarn install --check-files
|
36
|
+
|
37
|
+
EXPOSE 3000
|
38
|
+
|
39
|
+
ENTRYPOINT bin/rails server --port 3000 -b 0.0.0.0
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
2
|
+
# 1. STATE
|
3
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
4
|
+
|
5
|
+
terraform {
|
6
|
+
backend "s3" {
|
7
|
+
bucket = "<%= application_name %>-terraform-state-storage"
|
8
|
+
key = "terraform/<%= config[:env] %>-state/data"
|
9
|
+
region = "us-east-2"
|
10
|
+
dynamodb_table = "<%= application_name %>-terraform-state-lock"
|
11
|
+
encrypt = true
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
16
|
+
# 2. DB + S3 MODULE
|
17
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
18
|
+
|
19
|
+
variable "db_username" {}
|
20
|
+
variable "db_password" {}
|
21
|
+
|
22
|
+
module "db_and_s3" {
|
23
|
+
source = "github.com/charliereese/terraform_modules//data?ref=v0.0.6"
|
24
|
+
|
25
|
+
env = "<%= config[:env] %>"
|
26
|
+
app_name = "<%= application_name %>"
|
27
|
+
db_instance_class = "<%= config[:env] == 'prod' ? 'db.t3.micro' : 'db.t2.micro' %>"
|
28
|
+
db_encrypted = <%= config[:env] == 'prod' ? true : false %>
|
29
|
+
db_username = var.db_username
|
30
|
+
db_password = var.db_password
|
31
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
output "address" {
|
2
|
+
value = module.db_and_s3.address
|
3
|
+
description = "Connect to the database at this endpoint"
|
4
|
+
}
|
5
|
+
|
6
|
+
output "port" {
|
7
|
+
value = module.db_and_s3.port
|
8
|
+
description = "The port the database is listening on"
|
9
|
+
}
|
10
|
+
|
11
|
+
output "endpoint" {
|
12
|
+
value = module.db_and_s3.endpoint
|
13
|
+
description = "The endpoint of the databse"
|
14
|
+
}
|
15
|
+
|
16
|
+
output "db_name" {
|
17
|
+
value = module.db_and_s3.db_name
|
18
|
+
description = "The name of the database"
|
19
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Update to the latest current version of packages
|
4
|
+
sudo apt-get update
|
5
|
+
sudo apt -y install docker.io
|
6
|
+
docker --version
|
7
|
+
|
8
|
+
# # Start the Docker service
|
9
|
+
sudo service docker start
|
10
|
+
sudo usermod -aG docker ubuntu
|
11
|
+
|
12
|
+
# # Automatically start Docker service when the system boots, i.e. when the EC2 instance created from this AMI is launched or rebooted
|
13
|
+
sudo systemctl enable docker
|
14
|
+
|
15
|
+
# Log in
|
16
|
+
sudo docker login --username $DOCKERHUB_USERNAME -p $DOCKERHUB_ACCESS_TOKEN
|
17
|
+
|
18
|
+
# Run the container:
|
19
|
+
# --restart=always i.e. always start the container when the EC2 instance created from this AMI is launched or rebooted
|
20
|
+
# --detach , -d i.e. Run container in background and print container ID
|
21
|
+
# sudo docker run --restart=always USERNAME/<%= application_name %>:latest
|
22
|
+
sudo docker container run -p 3000:3000 --name <%= application_name %> --restart always -d $DOCKERHUB_USERNAME/<%= application_name %>:latest
|
@@ -0,0 +1,41 @@
|
|
1
|
+
{
|
2
|
+
"variables": {
|
3
|
+
"DOCKERHUB_ACCESS_TOKEN": "",
|
4
|
+
"DOCKERHUB_USERNAME": ""
|
5
|
+
},
|
6
|
+
|
7
|
+
"builders": [{
|
8
|
+
"type": "amazon-ebs",
|
9
|
+
"region": "us-east-2",
|
10
|
+
"source_ami_filter": {
|
11
|
+
"filters": {
|
12
|
+
"virtualization-type": "hvm",
|
13
|
+
"name": "ubuntu/images/*ubuntu-disco-19.04-amd64-server-*",
|
14
|
+
"root-device-type": "ebs"
|
15
|
+
},
|
16
|
+
"owners": ["099720109477"],
|
17
|
+
"most_recent": true
|
18
|
+
},
|
19
|
+
"instance_type": "t2.micro",
|
20
|
+
"ssh_username": "ubuntu",
|
21
|
+
"ami_name": "<%= application_name %>-ec2 {{timestamp}}",
|
22
|
+
"tags": {
|
23
|
+
"application": "<%= application_name %>-web-server"
|
24
|
+
}
|
25
|
+
}],
|
26
|
+
|
27
|
+
"provisioners": [{
|
28
|
+
"type": "shell",
|
29
|
+
"inline": [
|
30
|
+
"sleep 30"
|
31
|
+
]
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"type":"shell",
|
35
|
+
"environment_vars": [
|
36
|
+
"DOCKERHUB_ACCESS_TOKEN={{user `DOCKERHUB_ACCESS_TOKEN`}}",
|
37
|
+
"DOCKERHUB_USERNAME={{user `DOCKERHUB_USERNAME`}}"
|
38
|
+
],
|
39
|
+
"script": "ami_build.sh"
|
40
|
+
}]
|
41
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
2
|
+
# 1. STATE MODULE
|
3
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
4
|
+
|
5
|
+
module "remote_state_locking" {
|
6
|
+
source = "github.com/charliereese/terraform_modules//state?ref=v0.0.6"
|
7
|
+
|
8
|
+
app_name = "<%= application_name %>"
|
9
|
+
region = "us-east-2"
|
10
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
2
|
+
# 1. STATE
|
3
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
4
|
+
|
5
|
+
terraform {
|
6
|
+
backend "s3" {
|
7
|
+
bucket = "<%= application_name %>-terraform-state-storage"
|
8
|
+
key = "terraform/<%= config[:env] %>-state/web-servers"
|
9
|
+
region = "us-east-2"
|
10
|
+
dynamodb_table = "<%= application_name %>-terraform-state-lock"
|
11
|
+
encrypt = true
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
16
|
+
# 2. WEB SERVERS MODULE
|
17
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
18
|
+
|
19
|
+
module "webserver_cluster" {
|
20
|
+
source = "github.com/charliereese/terraform_modules//web_servers?ref=v0.0.6"
|
21
|
+
|
22
|
+
instance_type = "t2.micro"
|
23
|
+
env = "<%= config[:env] %>"
|
24
|
+
app_name = "<%= application_name %>"
|
25
|
+
domain_name = "<%= config[:domain_name] %>"
|
26
|
+
min_size = 1
|
27
|
+
max_size = 1
|
28
|
+
business_hours_size = 1
|
29
|
+
night_hours_size = 1
|
30
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
output "alb_dns_name" {
|
2
|
+
value = module.webserver_cluster.alb_dns_name
|
3
|
+
description = "The domain name of the application load balancer"
|
4
|
+
}
|
5
|
+
|
6
|
+
output "asg_name" {
|
7
|
+
value = module.webserver_cluster.asg_name
|
8
|
+
description = "autoscaling group name"
|
9
|
+
}
|
10
|
+
|
11
|
+
output "alb_security_group_id" {
|
12
|
+
value = module.webserver_cluster.alb_security_group_id
|
13
|
+
description = "ID of Security Group attached to ALB"
|
14
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "generators/extensions"
|
2
|
+
|
3
|
+
module TerraBoi
|
4
|
+
class WebServersGenerator < Rails::Generators::Base
|
5
|
+
attr_accessor :application_name, :class_options
|
6
|
+
class_option :domain_name, type: :string
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
8
|
+
|
9
|
+
desc (<<-EOF
|
10
|
+
Generate staging and production terraform web server files
|
11
|
+
|
12
|
+
To execute, run rails generate terra_boi:web_servers --domain_name example.com
|
13
|
+
EOF
|
14
|
+
.gsub(/\t/, '')
|
15
|
+
)
|
16
|
+
|
17
|
+
def init
|
18
|
+
# defined in lib/generators/extensions
|
19
|
+
self.application_name = generate_application_name
|
20
|
+
self.class_options = options
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_main_terraform_file
|
24
|
+
generate_terraform_files({
|
25
|
+
template: 'web_servers_main.erb',
|
26
|
+
file_path: 'web_servers/main.tf',
|
27
|
+
env: ['staging', 'prod']
|
28
|
+
})
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_output_terraform_file
|
32
|
+
generate_terraform_files({
|
33
|
+
template: 'web_servers_output.erb',
|
34
|
+
file_path: 'web_servers/output.tf',
|
35
|
+
env: ['staging', 'prod']
|
36
|
+
})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/terra_boi.rb
ADDED
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: terra_boi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Charlie Reese
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-09-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 6.0.0
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '6.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 6.0.0
|
33
|
+
description: 'This gem was created to get rails applications deployed into production
|
34
|
+
as quickly and easily as possible. It contains generators that create infrastructure
|
35
|
+
code for load balancing / auto scaling / zero-downtime deployments, (rails) web
|
36
|
+
apps (EC2 instances), DBs, and S3 buckets. List of items created by this gem''s
|
37
|
+
generators: Dockerfile, Rails initializer file (for setting up config.hosts), Packer
|
38
|
+
repository (for creating AWS EC2 AMIs), and Terraform repository (for creating infrastructure
|
39
|
+
as code to immediately deploy staging / prod infrastructure).'
|
40
|
+
email:
|
41
|
+
- j.charles.reese@gmail.com
|
42
|
+
executables: []
|
43
|
+
extensions: []
|
44
|
+
extra_rdoc_files: []
|
45
|
+
files:
|
46
|
+
- MIT-LICENSE
|
47
|
+
- README.md
|
48
|
+
- Rakefile
|
49
|
+
- lib/generators/extensions.rb
|
50
|
+
- lib/generators/terra_boi/boilerplate_generator.rb
|
51
|
+
- lib/generators/terra_boi/data_generator.rb
|
52
|
+
- lib/generators/terra_boi/dockerfile_generator.rb
|
53
|
+
- lib/generators/terra_boi/host_initializer_generator.rb
|
54
|
+
- lib/generators/terra_boi/packer_generator.rb
|
55
|
+
- lib/generators/terra_boi/state_generator.rb
|
56
|
+
- lib/generators/terra_boi/templates/Dockerfile.erb
|
57
|
+
- lib/generators/terra_boi/templates/data_main.erb
|
58
|
+
- lib/generators/terra_boi/templates/data_output.erb
|
59
|
+
- lib/generators/terra_boi/templates/host_initializer.erb
|
60
|
+
- lib/generators/terra_boi/templates/packer_ami_build.erb
|
61
|
+
- lib/generators/terra_boi/templates/packer_application.erb
|
62
|
+
- lib/generators/terra_boi/templates/state_main.erb
|
63
|
+
- lib/generators/terra_boi/templates/web_servers_main.erb
|
64
|
+
- lib/generators/terra_boi/templates/web_servers_output.erb
|
65
|
+
- lib/generators/terra_boi/web_servers_generator.rb
|
66
|
+
- lib/tasks/terra_boi_tasks.rake
|
67
|
+
- lib/terra_boi.rb
|
68
|
+
- lib/terra_boi/railtie.rb
|
69
|
+
- lib/terra_boi/version.rb
|
70
|
+
homepage: https://github.com/charliereese/terra_boi
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata: {}
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 2.7.7
|
91
|
+
signing_key:
|
92
|
+
specification_version: 4
|
93
|
+
summary: Generators to help you get rails applications deployed into production as
|
94
|
+
quickly and easily as possible.
|
95
|
+
test_files: []
|