Skip to content
Snippets Groups Projects
Commit b120576a authored by Iain R. Learmonth's avatar Iain R. Learmonth
Browse files

metrics convert all to markdown now

parent ea0dd76d
No related branches found
No related tags found
No related merge requests found
File moved
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<!-- 2020-04-02 Thu 14:12 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>metrics-cloud: Scripts for orchestrating Tor Metrics services</title>
<meta name="generator" content="Org mode" />
<meta name="author" content="Iain Learmonth" />
<style type="text/css">
<!--/*--><![CDATA[/*><!--*/
.title { text-align: center;
margin-bottom: .2em; }
.subtitle { text-align: center;
font-size: medium;
font-weight: bold;
margin-top:0; }
.todo { font-family: monospace; color: red; }
.done { font-family: monospace; color: green; }
.priority { font-family: monospace; color: orange; }
.tag { background-color: #eee; font-family: monospace;
padding: 2px; font-size: 80%; font-weight: normal; }
.timestamp { color: #bebebe; }
.timestamp-kwd { color: #5f9ea0; }
.org-right { margin-left: auto; margin-right: 0px; text-align: right; }
.org-left { margin-left: 0px; margin-right: auto; text-align: left; }
.org-center { margin-left: auto; margin-right: auto; text-align: center; }
.underline { text-decoration: underline; }
#postamble p, #preamble p { font-size: 90%; margin: .2em; }
p.verse { margin-left: 3%; }
pre {
border: 1px solid #ccc;
box-shadow: 3px 3px 3px #eee;
padding: 8pt;
font-family: monospace;
overflow: auto;
margin: 1.2em;
}
pre.src {
position: relative;
overflow: visible;
padding-top: 1.2em;
}
pre.src:before {
display: none;
position: absolute;
background-color: white;
top: -10px;
right: 10px;
padding: 3px;
border: 1px solid black;
}
pre.src:hover:before { display: inline;}
/* Languages per Org manual */
pre.src-asymptote:before { content: 'Asymptote'; }
pre.src-awk:before { content: 'Awk'; }
pre.src-C:before { content: 'C'; }
/* pre.src-C++ doesn't work in CSS */
pre.src-clojure:before { content: 'Clojure'; }
pre.src-css:before { content: 'CSS'; }
pre.src-D:before { content: 'D'; }
pre.src-ditaa:before { content: 'ditaa'; }
pre.src-dot:before { content: 'Graphviz'; }
pre.src-calc:before { content: 'Emacs Calc'; }
pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
pre.src-fortran:before { content: 'Fortran'; }
pre.src-gnuplot:before { content: 'gnuplot'; }
pre.src-haskell:before { content: 'Haskell'; }
pre.src-hledger:before { content: 'hledger'; }
pre.src-java:before { content: 'Java'; }
pre.src-js:before { content: 'Javascript'; }
pre.src-latex:before { content: 'LaTeX'; }
pre.src-ledger:before { content: 'Ledger'; }
pre.src-lisp:before { content: 'Lisp'; }
pre.src-lilypond:before { content: 'Lilypond'; }
pre.src-lua:before { content: 'Lua'; }
pre.src-matlab:before { content: 'MATLAB'; }
pre.src-mscgen:before { content: 'Mscgen'; }
pre.src-ocaml:before { content: 'Objective Caml'; }
pre.src-octave:before { content: 'Octave'; }
pre.src-org:before { content: 'Org mode'; }
pre.src-oz:before { content: 'OZ'; }
pre.src-plantuml:before { content: 'Plantuml'; }
pre.src-processing:before { content: 'Processing.js'; }
pre.src-python:before { content: 'Python'; }
pre.src-R:before { content: 'R'; }
pre.src-ruby:before { content: 'Ruby'; }
pre.src-sass:before { content: 'Sass'; }
pre.src-scheme:before { content: 'Scheme'; }
pre.src-screen:before { content: 'Gnu Screen'; }
pre.src-sed:before { content: 'Sed'; }
pre.src-sh:before { content: 'shell'; }
pre.src-sql:before { content: 'SQL'; }
pre.src-sqlite:before { content: 'SQLite'; }
/* additional languages in org.el's org-babel-load-languages alist */
pre.src-forth:before { content: 'Forth'; }
pre.src-io:before { content: 'IO'; }
pre.src-J:before { content: 'J'; }
pre.src-makefile:before { content: 'Makefile'; }
pre.src-maxima:before { content: 'Maxima'; }
pre.src-perl:before { content: 'Perl'; }
pre.src-picolisp:before { content: 'Pico Lisp'; }
pre.src-scala:before { content: 'Scala'; }
pre.src-shell:before { content: 'Shell Script'; }
pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
/* additional language identifiers per "defun org-babel-execute"
in ob-*.el */
pre.src-cpp:before { content: 'C++'; }
pre.src-abc:before { content: 'ABC'; }
pre.src-coq:before { content: 'Coq'; }
pre.src-groovy:before { content: 'Groovy'; }
/* additional language identifiers from org-babel-shell-names in
ob-shell.el: ob-shell is the only babel language using a lambda to put
the execution function name together. */
pre.src-bash:before { content: 'bash'; }
pre.src-csh:before { content: 'csh'; }
pre.src-ash:before { content: 'ash'; }
pre.src-dash:before { content: 'dash'; }
pre.src-ksh:before { content: 'ksh'; }
pre.src-mksh:before { content: 'mksh'; }
pre.src-posh:before { content: 'posh'; }
/* Additional Emacs modes also supported by the LaTeX listings package */
pre.src-ada:before { content: 'Ada'; }
pre.src-asm:before { content: 'Assembler'; }
pre.src-caml:before { content: 'Caml'; }
pre.src-delphi:before { content: 'Delphi'; }
pre.src-html:before { content: 'HTML'; }
pre.src-idl:before { content: 'IDL'; }
pre.src-mercury:before { content: 'Mercury'; }
pre.src-metapost:before { content: 'MetaPost'; }
pre.src-modula-2:before { content: 'Modula-2'; }
pre.src-pascal:before { content: 'Pascal'; }
pre.src-ps:before { content: 'PostScript'; }
pre.src-prolog:before { content: 'Prolog'; }
pre.src-simula:before { content: 'Simula'; }
pre.src-tcl:before { content: 'tcl'; }
pre.src-tex:before { content: 'TeX'; }
pre.src-plain-tex:before { content: 'Plain TeX'; }
pre.src-verilog:before { content: 'Verilog'; }
pre.src-vhdl:before { content: 'VHDL'; }
pre.src-xml:before { content: 'XML'; }
pre.src-nxml:before { content: 'XML'; }
/* add a generic configuration mode; LaTeX export needs an additional
(add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */
pre.src-conf:before { content: 'Configuration File'; }
table { border-collapse:collapse; }
caption.t-above { caption-side: top; }
caption.t-bottom { caption-side: bottom; }
td, th { vertical-align:top; }
th.org-right { text-align: center; }
th.org-left { text-align: center; }
th.org-center { text-align: center; }
td.org-right { text-align: right; }
td.org-left { text-align: left; }
td.org-center { text-align: center; }
dt { font-weight: bold; }
.footpara { display: inline; }
.footdef { margin-bottom: 1em; }
.figure { padding: 1em; }
.figure p { text-align: center; }
.inlinetask {
padding: 10px;
border: 2px solid gray;
margin: 10px;
background: #ffffcc;
}
#org-div-home-and-up
{ text-align: right; font-size: 70%; white-space: nowrap; }
textarea { overflow-x: auto; }
.linenr { font-size: smaller }
.code-highlighted { background-color: #ffff00; }
.org-info-js_info-navigation { border-style: none; }
#org-info-js_console-label
{ font-size: 10px; font-weight: bold; white-space: nowrap; }
.org-info-js_search-highlight
{ background-color: #ffff00; color: #000000; font-weight: bold; }
.org-svg { width: 90%; }
/*]]>*/-->
</style>
<script type="text/javascript">
/*
@licstart The following is the entire license notice for the
JavaScript code in this tag.
Copyright (C) 2012-2019 Free Software Foundation, Inc.
The JavaScript code in this tag is free software: you can
redistribute it and/or modify it under the terms of the GNU
General Public License (GNU GPL) as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version. The code is distributed WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
As additional permission under GNU GPL version 3 section 7, you
may distribute non-source (e.g., minimized or compacted) forms of
that code without the copy of the GNU GPL normally required by
section 4, provided you include this license notice and a URL
through which recipients can access the Corresponding Source.
@licend The above is the entire license notice
for the JavaScript code in this tag.
*/
<!--/*--><![CDATA[/*><!--*/
function CodeHighlightOn(elem, id)
{
var target = document.getElementById(id);
if(null != target) {
elem.cacheClassElem = elem.className;
elem.cacheClassTarget = target.className;
target.className = "code-highlighted";
elem.className = "code-highlighted";
}
}
function CodeHighlightOff(elem, id)
{
var target = document.getElementById(id);
if(elem.cacheClassElem)
elem.className = elem.cacheClassElem;
if(elem.cacheClassTarget)
target.className = elem.cacheClassTarget;
}
/*]]>*///-->
</script>
</head>
<body>
<div id="content">
<h1 class="title">metrics-cloud: Scripts for orchestrating Tor Metrics services</h1>
<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#org07a14d1">1. <span class="done DONE">DONE</span> Synopsis</a></li>
<li><a href="#org27d3c39">2. <span class="done DONE">DONE</span> Usage of AWS for Tor Metrics Development</a>
<ul>
<li><a href="#orga1a5ff9">2.1. <span class="done DONE">DONE</span> CloudFormation Templates</a>
<ul>
<li><a href="#org1bc4ee4">2.1.1. <span class="done DONE">DONE</span> Quickstart: Deploying a template</a></li>
<li><a href="#org1c05a7f">2.1.2. <span class="done DONE">DONE</span> SSH Key Selection</a></li>
</ul>
</li>
<li><a href="#org08aa3f4">2.2. <span class="done DONE">DONE</span> Templates and Stacks</a>
<ul>
<li><a href="#orgf227b70">2.2.1. <span class="done DONE">DONE</span> <code>billing-alerts</code></a></li>
<li><a href="#org235b822">2.2.2. <span class="done DONE">DONE</span> <code>metrics-vpc</code></a></li>
<li><a href="#org00ea298">2.2.3. <span class="done DONE">DONE</span> Typical Dev/Testing Stacks</a></li>
</ul>
</li>
<li><a href="#org421af3d">2.3. <span class="done DONE">DONE</span> Linting</a></li>
</ul>
</li>
<li><a href="#org472e401">3. <span class="todo TODO">TODO</span> Ansible Playbooks</a>
<ul>
<li><a href="#org5e8912e">3.1. <span class="todo TODO">TODO</span> Inventories and site.yml</a></li>
<li><a href="#org94fb36a">3.2. <span class="todo TODO">TODO</span> <code>metrics-common</code></a></li>
<li><a href="#org23da459">3.3. <span class="todo TODO">TODO</span> Service roles</a></li>
<li><a href="#org2eb6ad9">3.4. <span class="done DONE">DONE</span> Linting</a></li>
</ul>
</li>
<li><a href="#orgd132103">4. <span class="todo TODO">TODO</span> Common Tasks</a>
<ul>
<li><a href="#org5d856f9">4.1. <span class="todo TODO">TODO</span> Add a new member to the team</a></li>
<li><a href="#org61fca5a">4.2. <span class="todo TODO">TODO</span> Update an SSH key for a team member</a></li>
<li><a href="#orgf5526f2">4.3. <span class="todo TODO">TODO</span> Deploy and provision a development environment for a service</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div id="outline-container-org07a14d1" class="outline-2">
<h2 id="org07a14d1"><span class="section-number-2">1</span> <span class="done DONE">DONE</span> Synopsis</h2>
<div class="outline-text-2" id="text-1">
<p>
The metrics-cloud framework aims to enable:
</p>
<ul class="org-ul">
<li>reproducible deployments of software</li>
<li>consistency between those software deployments</li>
</ul>
<p>
Side-effects of these goals are:
</p>
<ul class="org-ul">
<li>reproducible experiments (good science)</li>
<li>reduced maintainence costs</li>
<li>reduced human error</li>
</ul>
<p>
There are currently two components to the metrics-cloud framework: CloudFormation templates and Ansible playbooks.
The CloudFormation templates are relevant only to testing and development, while the Ansible playbooks are applicable
to both environments.
</p>
</div>
</div>
<div id="outline-container-org27d3c39" class="outline-2">
<h2 id="org27d3c39"><span class="section-number-2">2</span> <span class="done DONE">DONE</span> Usage of AWS for Tor Metrics Development</h2>
<div class="outline-text-2" id="text-2">
<p>
Each member of the Tor Metrics team has a standing allowance of 100USD/month for development using AWS. In practice,
we have not used more than 50USD/month for the team in any one month and generally sit around 25USD/month. It is
still important to minimize costs when using AWS and the use of CloudFormation templates and Ansible playbooks for
rapid creation, provisioning and destruction should help with this.
</p>
</div>
<div id="outline-container-orga1a5ff9" class="outline-3">
<h3 id="orga1a5ff9"><span class="section-number-3">2.1</span> <span class="done DONE">DONE</span> CloudFormation Templates</h3>
<div class="outline-text-3" id="text-2-1">
<p>
CloudFormation is an AWS service allowing the definition of <i>stacks</i>. These stacks describe a series of AWS services
using a domain-specific language and allow for the easy creation of a number of interconnected resources. All resources
in a stack are tagged with the stack name which allows for tracking of costs per project. Each stack can also have all
resources terminated together easily, allowing stacks to exist for only as long as they are needed.
</p>
<p>
The CloudFormation templates used in the framework can be found in the <a href="https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation">cloudformation</a> folder of the repository.
</p>
<p>
It may be that for some services the templates are very simple, and others may be more complex. No matter the level of
complexity we still want to use the templates to ensure we are meeting the key goals of the framework and also to simplify
tracking of spending in the billing portal through the tags.
</p>
<p>
Documentation for CloudFormation, including an API reference, can be found at: <a href="https://docs.aws.amazon.com/cloudformation/">https://docs.aws.amazon.com/cloudformation/</a>.
</p>
</div>
<div id="outline-container-org1bc4ee4" class="outline-4">
<h4 id="org1bc4ee4"><span class="section-number-4">2.1.1</span> <span class="done DONE">DONE</span> Quickstart: Deploying a template</h4>
<div class="outline-text-4" id="text-2-1-1">
<p>
Each template begins with comments with any relevant notes about the template, and a deployment command that will upload
and deploy the template on AWS. The commands will look something like:
</p>
<div class="org-src-container">
<pre class="src src-shell">aws cloudformation deploy --region us-east-1 --stack-name <span style="color: #ff00ff;">`whoami`</span>-exit-scanner-dev --template-file exit-scanner-dev.yml --parameter-overrides <span style="color: #a0522d;">myKeyPair</span>=<span style="color: #8b2252;">"$(./identify_user.sh)"</span>
</pre>
</div>
<p>
You'll notice that the command includes a call to <code>whoami</code> to prefix the stack name with your current username, and also
that the <code>identify_user.sh</code> script is used to determine which SSH key to use for new instances.
You do not need to modify this command line before running it.
</p>
<p>
Once the stack has been deployed from the template, you can view its resources and delete it through
the <a href="https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks?filteringText=&amp;filteringStatus=active&amp;viewNested=true&amp;hideStacks=false">CloudFormation management console</a>.
</p>
</div>
</div>
<div id="outline-container-org1c05a7f" class="outline-4">
<h4 id="org1c05a7f"><span class="section-number-4">2.1.2</span> <span class="done DONE">DONE</span> SSH Key Selection</h4>
<div class="outline-text-4" id="text-2-1-2">
<p>
The <a href="https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation/identify_user.sh">identify_user.sh</a> script prints out the name of the SSH public key to be used based on either:
</p>
<ul class="org-ul">
<li>the <code>TOR_METRICS_SSH_KEY</code> environment variable, or</li>
<li>the current user name.</li>
</ul>
<p>
The environment variable takes precedence over the username to key mapping.
</p>
<p>
If you change the default key you would like to use, update the mapping in this shell script.
</p>
<p>
SSH keys are managed through the <a href="https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#KeyPairs:">EC2 management console</a> and are not (currently) managed by a CloudFormation template.
</p>
</div>
</div>
</div>
<div id="outline-container-org08aa3f4" class="outline-3">
<h3 id="org08aa3f4"><span class="section-number-3">2.2</span> <span class="done DONE">DONE</span> Templates and Stacks</h3>
<div class="outline-text-3" id="text-2-2">
<p>
There is no directory hierachy for the templates in the <code>cloudformation</code> folder of the repository. There are a couple of naming
conventions used though:
</p>
<ul class="org-ul">
<li>Development/testing templates/stacks use a <code>-dev</code> suffix after the service name</li>
<li>Long-term and shared templates/stacks start with <code>metrics-</code></li>
</ul>
</div>
<div id="outline-container-orgf227b70" class="outline-4">
<h4 id="orgf227b70"><span class="section-number-4">2.2.1</span> <span class="done DONE">DONE</span> <code>billing-alerts</code></h4>
<div class="outline-text-4" id="text-2-2-1">
<p>
The <a href="https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation/billing-alerts.yml"><code>billing-alerts</code> template</a> sends notifications to the subscribed individuals whenever the predicted spend for the month will be
over 50USD. Email addresses can be added here if other people should be notified too.
</p>
</div>
</div>
<div id="outline-container-org235b822" class="outline-4">
<h4 id="org235b822"><span class="section-number-4">2.2.2</span> <span class="done DONE">DONE</span> <code>metrics-vpc</code></h4>
<div class="outline-text-4" id="text-2-2-2">
<p>
The <a href="https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation/metrics-vpc.yml"><code>metrics-vpc</code> template</a> contains shared resources for Tor Metrics development templates. This includes:
</p>
</div>
<ol class="org-ol">
<li><a id="orgda50584"></a>MetricsVPC and MetricsSubnet<br />
<div class="outline-text-5" id="text-2-2-2-1">
<p>
The subnet should be referenced by any resource that requires it. Use of the default VPC should be avoided as we
share the AWS account with other Tor teams.
</p>
<p>
For example, to create an EC2 instance:
</p>
<div class="org-src-container">
<pre class="src src-yaml">Instance:
Type: AWS::EC2::Instance
Properties:
AvailabilityZone: !Select [ 0, !GetAZs ]
ImageId: ami-01db78123b2b99496
InstanceType: t2.large
SubnetId:
Fn::ImportValue: 'MetricsSubnet'
KeyName: !Ref myKeyPair
SecurityGroupIds:
- Fn::ImportValue: 'MetricsInternetSecurityGroup'
- Fn::ImportValue: 'MetricsPingableSecurityGroup'
- Fn::ImportValue: 'MetricsHTTPASecurityGroup'
</pre>
</div>
<p>
Note also that the availability zone is not hardcoded to allow for portability between regions if we ever want that.
</p>
</div>
</li>
<li><a id="orgdfe9221"></a>Various security groups<br />
<div class="outline-text-5" id="text-2-2-2-2">
<p>
The EC2 example above uses some of the security groups from the <code>metrics-vpc</code> template. Refer to the template source
for details on each group's rules.
</p>
</div>
</li>
<li><a id="org1be7f33"></a>The development DNS zone<br />
<div class="outline-text-5" id="text-2-2-2-3">
<p>
Often services require TLS certificates, or require DNS names for other reasons. To facilitate this, a zone is hosted
using Route53 allowing for DNS records to be created in CloudFormation templates. This zone is:
<code>tm-dev-aws.safemetrics.org</code>.
</p>
<p>
As an example, creating an A record for an EC2 instance with the subdomain of the stack name:
</p>
<div class="org-src-container">
<pre class="src src-yaml">DNSName:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: tm-dev-aws.safemetrics.org.
Name: !Join ['', [!Ref 'AWS::StackName', .tm-dev-aws.safemetrics.org.]]
Type: A
TTL: '300'
ResourceRecords:
- !GetAtt Instance.PublicIp
</pre>
</div>
<p>
Q: <i>Can we use the MetricsDevZone export from <code>metrics-vpc</code> instead of explicitly defining the zone name every time?</i>
</p>
<p>
These domain names should <b>never</b> appear on anything user facing and are for <b>development purposes only</b>.
</p>
</div>
</li>
</ol>
</div>
<div id="outline-container-org00ea298" class="outline-4">
<h4 id="org00ea298"><span class="section-number-4">2.2.3</span> <span class="done DONE">DONE</span> Typical Dev/Testing Stacks</h4>
<div class="outline-text-4" id="text-2-2-3">
<p>
A typical test/dev stack will consist of an EC2 instance and a DNS name. Some services store a lot of data and may have
a second volume attached for the data storage.
</p>
<p>
An example template with one t2.large EC2 instance, a 15GB additional disk, and a DNS name:
</p>
<div class="org-src-container">
<pre class="src src-yaml">---
# CloudFormation Stack for example development instance
# This stack will only deploy on us-east-1 and will deploy in the Metrics VPC
# aws cloudformation deploy --region us-east-1 --stack-name `whoami`-example-dev --template-file example-dev.yml --parameter-overrides myKeyPair="$(./identify_user.sh)"
AWSTemplateFormatVersion: 2010-09-09
Parameters:
myKeyPair:
Description: Amazon EC2 Key Pair
Type: "AWS::EC2::KeyPair::KeyName"
Resources:
Instance:
Type: AWS::EC2::Instance
Properties:
AvailabilityZone: !Select [ 0, !GetAZs ]
ImageId: ami-01db78123b2b99496
InstanceType: t2.large
SubnetId:
Fn::ImportValue: 'MetricsSubnet'
KeyName: !Ref myKeyPair
SecurityGroupIds:
- Fn::ImportValue: 'MetricsInternetSecurityGroup'
- Fn::ImportValue: 'MetricsPingableSecurityGroup'
- Fn::ImportValue: 'MetricsHTTPSecurityGroup'
- Fn::ImportValue: 'MetricsHTTPSSecurityGroup'
ServiceVolume:
Type: AWS::EC2::Volume
Properties:
AvailabilityZone: !Select [ 0, !GetAZs ]
Size: 15
VolumeType: gp2
ServiceVolumeAttachment:
Type: AWS::EC2::VolumeAttachment
Properties:
Device: /dev/sdb
InstanceId: !Ref Instance
VolumeId: !Ref ServiceVolume
DNSName:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: tm-dev-aws.safemetrics.org.
Name: !Join ['', [!Ref 'AWS::StackName', .tm-dev-aws.safemetrics.org.]]
Type: A
TTL: '300'
ResourceRecords:
- !GetAtt Instance.PublicIp
Outputs:
PublicIp:
Description: "Instance public IP"
Value: !GetAtt Instance.PublicIp
</pre>
</div>
<p>
It's not common to use other AWS services as part of these templates as the goal is usually to have these services
deployed on TPA managed hosts.
</p>
</div>
</div>
</div>
<div id="outline-container-org421af3d" class="outline-3">
<h3 id="org421af3d"><span class="section-number-3">2.3</span> <span class="done DONE">DONE</span> Linting</h3>
<div class="outline-text-3" id="text-2-3">
<p>
<a href="https://github.com/aws-cloudformation/cfn-python-lint"><code>cfn-lint</code></a> is used to ensure we are complying with best practices. None of the team have formal training in the use of CloudFormation
so we are really making it up as we go along. Other tools may be used in the future, as we learn about them, to make sure we are using
things efficiently and correctly.
</p>
<p>
This is also run as part of the <a href="https://travis-ci.org/github/torproject/metrics-cloud/">continuous integration checks</a> on Travis CI.
</p>
</div>
</div>
</div>
<div id="outline-container-org472e401" class="outline-2">
<h2 id="org472e401"><span class="section-number-2">3</span> <span class="todo TODO">TODO</span> Ansible Playbooks</h2>
<div class="outline-text-2" id="text-3">
<p>
Ansible is an open-source software provisioning, configuration management, and application-deployment tool. It's written in Python,
is mature, and has an extensive selection of modules for almost everything we could need.
</p>
</div>
<div id="outline-container-org5e8912e" class="outline-3">
<h3 id="org5e8912e"><span class="section-number-3">3.1</span> <span class="todo TODO">TODO</span> Inventories and site.yml</h3>
<div class="outline-text-3" id="text-3-1">
<p>
In general, there are two inventories: <a href="https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/production">production</a> and dev. Only the production inventory is committed to git, the dev inventory will
vary between members of the team, referencing their own dev instances as created by CloudFormation. We do not specify a default
inventory in the <code>ansible.cfg</code> file, so you must specify an inventory for every invocation of <code>ansible-playbook</code> using the <code>-i</code> flag:
</p>
<div class="org-src-container">
<pre class="src src-shell">ansible-playbook -i dev ...
</pre>
</div>
<p>
Inside the inventory, hosts are grouped by their purpose. For each group there is a corresponding YAML file in the root of the
<code>ansible</code> directory that specifies a playbook for the group. All of these files are included in the <code>site.yml</code> master playbook to
allow multiple hosts to be provisioned together.
</p>
</div>
</div>
<div id="outline-container-org94fb36a" class="outline-3">
<h3 id="org94fb36a"><span class="section-number-3">3.2</span> <span class="todo TODO">TODO</span> <code>metrics-common</code></h3>
<div class="outline-text-3" id="text-3-2">
<p>
The <a href="https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/roles/metrics-common"><code>metrics-common</code></a> role allows us to have a consistent environment between services, and closely matches the environment that
would be provided by a TSA managed machine. The role handles:
</p>
<ul class="org-ul">
<li>installation of dependency packages from Debian (optionally from the backports repository)</li>
<li>formats additional volumes attached to the instance using the specified filesystem</li>
<li>sets the timezone to UTC (Q: <i>is this what TSA do?</i>)</li>
<li>creates user accounts for each member of the team
<ul class="org-ul">
<li>all team members can perform unlimited passwordless sudo (TSA hosts require a password)</li>
<li>SSH password authentication is disabled</li>
<li>all user account passwords are removed/disabled</li>
</ul></li>
<li>creates service user accounts as specified
<ul class="org-ul">
<li>home directories are created as specified, and linked from <code>/home/$user</code></li>
<li>lingering is enabled for service users</li>
</ul></li>
</ul>
<p>
This is all configured via group variables in the <a href="https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/group_vars"><code>ansible/group_vars/</code></a> folder. Examples there should help you to understand how
these work. These override the <a href="https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/roles/metrics-common/defaults/main.yml">defaults</a> set in the role.
</p>
</div>
</div>
<div id="outline-container-org23da459" class="outline-3">
<h3 id="org23da459"><span class="section-number-3">3.3</span> <span class="todo TODO">TODO</span> Service roles</h3>
</div>
<div id="outline-container-org2eb6ad9" class="outline-3">
<h3 id="org2eb6ad9"><span class="section-number-3">3.4</span> <span class="done DONE">DONE</span> Linting</h3>
<div class="outline-text-3" id="text-3-4">
<p>
<a href="https://docs.ansible.com/ansible-lint/"><code>ansible-lint</code></a> is used to ensure we are complying with best practices. None of the team have formal training in the use of Ansible
so we are really making it up as we go along. Other tools may be used in the future, as we learn about them, to make sure we are using
things efficiently and correctly.
</p>
<p>
This is also run as part of the <a href="https://travis-ci.org/github/torproject/metrics-cloud/">continuous integration checks</a> on Travis CI.
</p>
</div>
</div>
</div>
<div id="outline-container-orgd132103" class="outline-2">
<h2 id="orgd132103"><span class="section-number-2">4</span> <span class="todo TODO">TODO</span> Common Tasks</h2>
<div class="outline-text-2" id="text-4">
</div>
<div id="outline-container-org5d856f9" class="outline-3">
<h3 id="org5d856f9"><span class="section-number-3">4.1</span> <span class="todo TODO">TODO</span> Add a new member to the team</h3>
</div>
<div id="outline-container-org61fca5a" class="outline-3">
<h3 id="org61fca5a"><span class="section-number-3">4.2</span> <span class="todo TODO">TODO</span> Update an SSH key for a team member</h3>
</div>
<div id="outline-container-orgf5526f2" class="outline-3">
<h3 id="orgf5526f2"><span class="section-number-3">4.3</span> <span class="todo TODO">TODO</span> Deploy and provision a development environment for a service</h3>
</div>
</div>
</div>
<div id="postamble" class="status">
<p class="author">Author: Iain Learmonth</p>
<p class="date">Created: 2020-04-02 Thu 14:12</p>
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
</body>
</html>
# Table of Contents
1. [Synopsis](#orgb3a4817)
2. [Usage of AWS for Tor Metrics Development](#orgb76cd81)
1. [CloudFormation Templates](#orgee150b1)
1. [Quickstart: Deploying a template](#org7813a03)
2. [SSH Key Selection](#orgdc7711c)
2. [Templates and Stacks](#org19b1306)
1. [`billing-alerts`](#org1b9ae57)
2. [`metrics-vpc`](#org2c178f5)
3. [Typical Dev/Testing Stacks](#org97f9e67)
3. [Linting](#orga89e157)
3. [Ansible Playbooks](#org8371364)
1. [Inventories and site.yml](#org81a0dc9)
2. [`metrics-common`](#org55e2902)
3. [Service roles](#org7050aae)
4. [Linting](#org9684f51)
4. [Common Tasks](#org8267248)
1. [Add a new member to the team](#org9040a14)
2. [Update an SSH key for a team member](#org97696ab)
3. [Deploy and provision a development environment for a service](#org400659a)
<a id="orgb3a4817"></a>
# DONE Synopsis
The metrics-cloud framework aims to enable:
- reproducible deployments of software
- consistency between those software deployments
Side-effects of these goals are:
- reproducible experiments (good science)
- reduced maintainence costs
- reduced human error
There are currently two components to the metrics-cloud framework: CloudFormation templates and Ansible playbooks.
The CloudFormation templates are relevant only to testing and development, while the Ansible playbooks are applicable
to both environments.
<a id="orgb76cd81"></a>
# DONE Usage of AWS for Tor Metrics Development
Each member of the Tor Metrics team has a standing allowance of 100USD/month for development using AWS. In practice,
we have not used more than 50USD/month for the team in any one month and generally sit around 25USD/month. It is
still important to minimize costs when using AWS and the use of CloudFormation templates and Ansible playbooks for
rapid creation, provisioning and destruction should help with this.
<a id="orgee150b1"></a>
## DONE CloudFormation Templates
CloudFormation is an AWS service allowing the definition of *stacks*. These stacks describe a series of AWS services
using a domain-specific language and allow for the easy creation of a number of interconnected resources. All resources
in a stack are tagged with the stack name which allows for tracking of costs per project. Each stack can also have all
resources terminated together easily, allowing stacks to exist for only as long as they are needed.
The CloudFormation templates used in the framework can be found in the [cloudformation](https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation) folder of the repository.
It may be that for some services the templates are very simple, and others may be more complex. No matter the level of
complexity we still want to use the templates to ensure we are meeting the key goals of the framework and also to simplify
tracking of spending in the billing portal through the tags.
Documentation for CloudFormation, including an API reference, can be found at: <https://docs.aws.amazon.com/cloudformation/>.
<a id="org7813a03"></a>
### DONE Quickstart: Deploying a template
Each template begins with comments with any relevant notes about the template, and a deployment command that will upload
and deploy the template on AWS. The commands will look something like:
aws cloudformation deploy --region us-east-1 --stack-name `whoami`-exit-scanner-dev --template-file exit-scanner-dev.yml --parameter-overrides myKeyPair="$(./identify_user.sh)"
You'll notice that the command includes a call to `whoami` to prefix the stack name with your current username, and also
that the `identify_user.sh` script is used to determine which SSH key to use for new instances.
You do not need to modify this command line before running it.
Once the stack has been deployed from the template, you can view its resources and delete it through
the [CloudFormation management console](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks?filteringText=&filteringStatus=active&viewNested=true&hideStacks=false).
<a id="orgdc7711c"></a>
### DONE SSH Key Selection
The [identify\_user.sh](https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation/identify_user.sh) script prints out the name of the SSH public key to be used based on either:
- the `TOR_METRICS_SSH_KEY` environment variable, or
- the current user name.
The environment variable takes precedence over the username to key mapping.
If you change the default key you would like to use, update the mapping in this shell script.
SSH keys are managed through the [EC2 management console](https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#KeyPairs:) and are not (currently) managed by a CloudFormation template.
<a id="org19b1306"></a>
## DONE Templates and Stacks
There is no directory hierachy for the templates in the `cloudformation` folder of the repository. There are a couple of naming
conventions used though:
- Development/testing templates/stacks use a `-dev` suffix after the service name
- Long-term and shared templates/stacks start with `metrics-`
<a id="org1b9ae57"></a>
### DONE `billing-alerts`
The [`billing-alerts` template](https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation/billing-alerts.yml) sends notifications to the subscribed individuals whenever the predicted spend for the month will be
over 50USD. Email addresses can be added here if other people should be notified too.
<a id="org2c178f5"></a>
### DONE `metrics-vpc`
The [`metrics-vpc` template](https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation/metrics-vpc.yml) contains shared resources for Tor Metrics development templates. This includes:
1. MetricsVPC and MetricsSubnet
The subnet should be referenced by any resource that requires it. Use of the default VPC should be avoided as we
share the AWS account with other Tor teams.
For example, to create an EC2 instance:
Instance:
Type: AWS::EC2::Instance
Properties:
AvailabilityZone: !Select [ 0, !GetAZs ]
ImageId: ami-01db78123b2b99496
InstanceType: t2.large
SubnetId:
Fn::ImportValue: 'MetricsSubnet'
KeyName: !Ref myKeyPair
SecurityGroupIds:
- Fn::ImportValue: 'MetricsInternetSecurityGroup'
- Fn::ImportValue: 'MetricsPingableSecurityGroup'
- Fn::ImportValue: 'MetricsHTTPASecurityGroup'
Note also that the availability zone is not hardcoded to allow for portability between regions if we ever want that.
2. Various security groups
The EC2 example above uses some of the security groups from the `metrics-vpc` template. Refer to the template source
for details on each group's rules.
3. The development DNS zone
Often services require TLS certificates, or require DNS names for other reasons. To facilitate this, a zone is hosted
using Route53 allowing for DNS records to be created in CloudFormation templates. This zone is:
`tm-dev-aws.safemetrics.org`.
As an example, creating an A record for an EC2 instance with the subdomain of the stack name:
DNSName:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: tm-dev-aws.safemetrics.org.
Name: !Join ['', [!Ref 'AWS::StackName', .tm-dev-aws.safemetrics.org.]]
Type: A
TTL: '300'
ResourceRecords:
- !GetAtt Instance.PublicIp
Q: *Can we use the MetricsDevZone export from `metrics-vpc` instead of explicitly defining the zone name every time?*
These domain names should **never** appear on anything user facing and are for **development purposes only**.
<a id="org97f9e67"></a>
### DONE Typical Dev/Testing Stacks
A typical test/dev stack will consist of an EC2 instance and a DNS name. Some services store a lot of data and may have
a second volume attached for the data storage.
An example template with one t2.large EC2 instance, a 15GB additional disk, and a DNS name:
---
# CloudFormation Stack for example development instance
# This stack will only deploy on us-east-1 and will deploy in the Metrics VPC
# aws cloudformation deploy --region us-east-1 --stack-name `whoami`-example-dev --template-file example-dev.yml --parameter-overrides myKeyPair="$(./identify_user.sh)"
AWSTemplateFormatVersion: 2010-09-09
Parameters:
myKeyPair:
Description: Amazon EC2 Key Pair
Type: "AWS::EC2::KeyPair::KeyName"
Resources:
Instance:
Type: AWS::EC2::Instance
Properties:
AvailabilityZone: !Select [ 0, !GetAZs ]
ImageId: ami-01db78123b2b99496
InstanceType: t2.large
SubnetId:
Fn::ImportValue: 'MetricsSubnet'
KeyName: !Ref myKeyPair
SecurityGroupIds:
- Fn::ImportValue: 'MetricsInternetSecurityGroup'
- Fn::ImportValue: 'MetricsPingableSecurityGroup'
- Fn::ImportValue: 'MetricsHTTPSecurityGroup'
- Fn::ImportValue: 'MetricsHTTPSSecurityGroup'
ServiceVolume:
Type: AWS::EC2::Volume
Properties:
AvailabilityZone: !Select [ 0, !GetAZs ]
Size: 15
VolumeType: gp2
ServiceVolumeAttachment:
Type: AWS::EC2::VolumeAttachment
Properties:
Device: /dev/sdb
InstanceId: !Ref Instance
VolumeId: !Ref ServiceVolume
DNSName:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: tm-dev-aws.safemetrics.org.
Name: !Join ['', [!Ref 'AWS::StackName', .tm-dev-aws.safemetrics.org.]]
Type: A
TTL: '300'
ResourceRecords:
- !GetAtt Instance.PublicIp
Outputs:
PublicIp:
Description: "Instance public IP"
Value: !GetAtt Instance.PublicIp
It's not common to use other AWS services as part of these templates as the goal is usually to have these services
deployed on TPA managed hosts.
<a id="orga89e157"></a>
## DONE Linting
[`cfn-lint`](https://github.com/aws-cloudformation/cfn-python-lint) is used to ensure we are complying with best practices. None of the team have formal training in the use of CloudFormation
so we are really making it up as we go along. Other tools may be used in the future, as we learn about them, to make sure we are using
things efficiently and correctly.
This is also run as part of the [continuous integration checks](https://travis-ci.org/github/torproject/metrics-cloud/) on Travis CI.
<a id="org8371364"></a>
# TODO Ansible Playbooks
Ansible is an open-source software provisioning, configuration management, and application-deployment tool. It's written in Python,
is mature, and has an extensive selection of modules for almost everything we could need.
<a id="org81a0dc9"></a>
## TODO Inventories and site.yml
In general, there are two inventories: [production](https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/production) and dev. Only the production inventory is committed to git, the dev inventory will
vary between members of the team, referencing their own dev instances as created by CloudFormation. We do not specify a default
inventory in the `ansible.cfg` file, so you must specify an inventory for every invocation of `ansible-playbook` using the `-i` flag:
ansible-playbook -i dev ...
Inside the inventory, hosts are grouped by their purpose. For each group there is a corresponding YAML file in the root of the
`ansible` directory that specifies a playbook for the group. All of these files are included in the `site.yml` master playbook to
allow multiple hosts to be provisioned together.
<a id="org55e2902"></a>
## TODO `metrics-common`
The [`metrics-common`](https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/roles/metrics-common) role allows us to have a consistent environment between services, and closely matches the environment that
would be provided by a TSA managed machine. The role handles:
- installation of dependency packages from Debian (optionally from the backports repository)
- formats additional volumes attached to the instance using the specified filesystem
- sets the timezone to UTC (Q: *is this what TSA do?*)
- creates user accounts for each member of the team
- all team members can perform unlimited passwordless sudo (TSA hosts require a password)
- SSH password authentication is disabled
- all user account passwords are removed/disabled
- creates service user accounts as specified
- home directories are created as specified, and linked from `/home/$user`
- lingering is enabled for service users
This is all configured via group variables in the [`ansible/group_vars/`](https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/group_vars) folder. Examples there should help you to understand how
these work. These override the [defaults](https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/roles/metrics-common/defaults/main.yml) set in the role.
<a id="org7050aae"></a>
## TODO Service roles
<a id="org9684f51"></a>
## DONE Linting
[`ansible-lint`](https://docs.ansible.com/ansible-lint/) is used to ensure we are complying with best practices. None of the team have formal training in the use of Ansible
so we are really making it up as we go along. Other tools may be used in the future, as we learn about them, to make sure we are using
things efficiently and correctly.
This is also run as part of the [continuous integration checks](https://travis-ci.org/github/torproject/metrics-cloud/) on Travis CI.
<a id="org8267248"></a>
# TODO Common Tasks
<a id="org9040a14"></a>
## TODO Add a new member to the team
<a id="org97696ab"></a>
## TODO Update an SSH key for a team member
<a id="org400659a"></a>
## TODO Deploy and provision a development environment for a service
#+TITLE: metrics-cloud: Scripts for orchestrating Tor Metrics services
#+OPTIONS: ^:nil
* DONE Synopsis
The metrics-cloud framework aims to enable:
- reproducible deployments of software
- consistency between those software deployments
Side-effects of these goals are:
- reproducible experiments (good science)
- reduced maintainence costs
- reduced human error
There are currently two components to the metrics-cloud framework: CloudFormation templates and Ansible playbooks.
The CloudFormation templates are relevant only to testing and development, while the Ansible playbooks are applicable
to both environments.
* DONE Usage of AWS for Tor Metrics Development
Each member of the Tor Metrics team has a standing allowance of 100USD/month for development using AWS. In practice,
we have not used more than 50USD/month for the team in any one month and generally sit around 25USD/month. It is
still important to minimize costs when using AWS and the use of CloudFormation templates and Ansible playbooks for
rapid creation, provisioning and destruction should help with this.
** DONE CloudFormation Templates
CloudFormation is an AWS service allowing the definition of /stacks/. These stacks describe a series of AWS services
using a domain-specific language and allow for the easy creation of a number of interconnected resources. All resources
in a stack are tagged with the stack name which allows for tracking of costs per project. Each stack can also have all
resources terminated together easily, allowing stacks to exist for only as long as they are needed.
The CloudFormation templates used in the framework can be found in the [[https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation][cloudformation]] folder of the repository.
It may be that for some services the templates are very simple, and others may be more complex. No matter the level of
complexity we still want to use the templates to ensure we are meeting the key goals of the framework and also to simplify
tracking of spending in the billing portal through the tags.
Documentation for CloudFormation, including an API reference, can be found at: https://docs.aws.amazon.com/cloudformation/.
*** DONE Quickstart: Deploying a template
Each template begins with comments with any relevant notes about the template, and a deployment command that will upload
and deploy the template on AWS. The commands will look something like:
#+BEGIN_SRC shell
aws cloudformation deploy --region us-east-1 --stack-name `whoami`-exit-scanner-dev --template-file exit-scanner-dev.yml --parameter-overrides myKeyPair="$(./identify_user.sh)"
#+END_SRC
You'll notice that the command includes a call to ~whoami~ to prefix the stack name with your current username, and also
that the ~identify_user.sh~ script is used to determine which SSH key to use for new instances.
You do not need to modify this command line before running it.
Once the stack has been deployed from the template, you can view its resources and delete it through
the [[https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks?filteringText=&filteringStatus=active&viewNested=true&hideStacks=false][CloudFormation management console]].
*** DONE SSH Key Selection
The [[https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation/identify_user.sh][identify_user.sh]] script prints out the name of the SSH public key to be used based on either:
- the ~TOR_METRICS_SSH_KEY~ environment variable, or
- the current user name.
The environment variable takes precedence over the username to key mapping.
If you change the default key you would like to use, update the mapping in this shell script.
SSH keys are managed through the [[https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#KeyPairs:][EC2 management console]] and are not (currently) managed by a CloudFormation template.
** DONE Templates and Stacks
There is no directory hierachy for the templates in the ~cloudformation~ folder of the repository. There are a couple of naming
conventions used though:
- Development/testing templates/stacks use a ~-dev~ suffix after the service name
- Long-term and shared templates/stacks start with ~metrics-~
*** DONE ~billing-alerts~
The [[https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation/billing-alerts.yml][~billing-alerts~ template]] sends notifications to the subscribed individuals whenever the predicted spend for the month will be
over 50USD. Email addresses can be added here if other people should be notified too.
*** DONE ~metrics-vpc~
The [[https://gitweb.torproject.org/metrics-cloud.git/tree/cloudformation/metrics-vpc.yml][~metrics-vpc~ template]] contains shared resources for Tor Metrics development templates. This includes:
**** MetricsVPC and MetricsSubnet
The subnet should be referenced by any resource that requires it. Use of the default VPC should be avoided as we
share the AWS account with other Tor teams.
For example, to create an EC2 instance:
#+BEGIN_SRC yaml
Instance:
Type: AWS::EC2::Instance
Properties:
AvailabilityZone: !Select [ 0, !GetAZs ]
ImageId: ami-01db78123b2b99496
InstanceType: t2.large
SubnetId:
Fn::ImportValue: 'MetricsSubnet'
KeyName: !Ref myKeyPair
SecurityGroupIds:
- Fn::ImportValue: 'MetricsInternetSecurityGroup'
- Fn::ImportValue: 'MetricsPingableSecurityGroup'
- Fn::ImportValue: 'MetricsHTTPASecurityGroup'
#+END_SRC
Note also that the availability zone is not hardcoded to allow for portability between regions if we ever want that.
**** Various security groups
The EC2 example above uses some of the security groups from the ~metrics-vpc~ template. Refer to the template source
for details on each group's rules.
**** The development DNS zone
Often services require TLS certificates, or require DNS names for other reasons. To facilitate this, a zone is hosted
using Route53 allowing for DNS records to be created in CloudFormation templates. This zone is:
~tm-dev-aws.safemetrics.org~.
As an example, creating an A record for an EC2 instance with the subdomain of the stack name:
#+BEGIN_SRC yaml
DNSName:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: tm-dev-aws.safemetrics.org.
Name: !Join ['', [!Ref 'AWS::StackName', .tm-dev-aws.safemetrics.org.]]
Type: A
TTL: '300'
ResourceRecords:
- !GetAtt Instance.PublicIp
#+END_SRC
:FUTUREQUESTION:
Q: /Can we use the MetricsDevZone export from ~metrics-vpc~ instead of explicitly defining the zone name every time?/
:END:
These domain names should *never* appear on anything user facing and are for *development purposes only*.
*** DONE Typical Dev/Testing Stacks
A typical test/dev stack will consist of an EC2 instance and a DNS name. Some services store a lot of data and may have
a second volume attached for the data storage.
An example template with one t2.large EC2 instance, a 15GB additional disk, and a DNS name:
#+BEGIN_SRC yaml
---
# CloudFormation Stack for example development instance
# This stack will only deploy on us-east-1 and will deploy in the Metrics VPC
# aws cloudformation deploy --region us-east-1 --stack-name `whoami`-example-dev --template-file example-dev.yml --parameter-overrides myKeyPair="$(./identify_user.sh)"
AWSTemplateFormatVersion: 2010-09-09
Parameters:
myKeyPair:
Description: Amazon EC2 Key Pair
Type: "AWS::EC2::KeyPair::KeyName"
Resources:
Instance:
Type: AWS::EC2::Instance
Properties:
AvailabilityZone: !Select [ 0, !GetAZs ]
ImageId: ami-01db78123b2b99496
InstanceType: t2.large
SubnetId:
Fn::ImportValue: 'MetricsSubnet'
KeyName: !Ref myKeyPair
SecurityGroupIds:
- Fn::ImportValue: 'MetricsInternetSecurityGroup'
- Fn::ImportValue: 'MetricsPingableSecurityGroup'
- Fn::ImportValue: 'MetricsHTTPSecurityGroup'
- Fn::ImportValue: 'MetricsHTTPSSecurityGroup'
ServiceVolume:
Type: AWS::EC2::Volume
Properties:
AvailabilityZone: !Select [ 0, !GetAZs ]
Size: 15
VolumeType: gp2
ServiceVolumeAttachment:
Type: AWS::EC2::VolumeAttachment
Properties:
Device: /dev/sdb
InstanceId: !Ref Instance
VolumeId: !Ref ServiceVolume
DNSName:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: tm-dev-aws.safemetrics.org.
Name: !Join ['', [!Ref 'AWS::StackName', .tm-dev-aws.safemetrics.org.]]
Type: A
TTL: '300'
ResourceRecords:
- !GetAtt Instance.PublicIp
Outputs:
PublicIp:
Description: "Instance public IP"
Value: !GetAtt Instance.PublicIp
#+END_SRC
It's not common to use other AWS services as part of these templates as the goal is usually to have these services
deployed on TPA managed hosts.
** DONE Linting
[[https://github.com/aws-cloudformation/cfn-python-lint][~cfn-lint~]] is used to ensure we are complying with best practices. None of the team have formal training in the use of CloudFormation
so we are really making it up as we go along. Other tools may be used in the future, as we learn about them, to make sure we are using
things efficiently and correctly.
This is also run as part of the [[https://travis-ci.org/github/torproject/metrics-cloud/][continuous integration checks]] on Travis CI.
* TODO Ansible Playbooks
Ansible is an open-source software provisioning, configuration management, and application-deployment tool. It's written in Python,
is mature, and has an extensive selection of modules for almost everything we could need.
** TODO Inventories and site.yml
In general, there are two inventories: [[https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/production][production]] and dev. Only the production inventory is committed to git, the dev inventory will
vary between members of the team, referencing their own dev instances as created by CloudFormation. We do not specify a default
inventory in the ~ansible.cfg~ file, so you must specify an inventory for every invocation of ~ansible-playbook~ using the ~-i~ flag:
#+BEGIN_SRC shell
ansible-playbook -i dev ...
#+END_SRC
Inside the inventory, hosts are grouped by their purpose. For each group there is a corresponding YAML file in the root of the
~ansible~ directory that specifies a playbook for the group. All of these files are included in the ~site.yml~ master playbook to
allow multiple hosts to be provisioned together.
** TODO ~metrics-common~
The [[https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/roles/metrics-common][~metrics-common~]] role allows us to have a consistent environment between services, and closely matches the environment that
would be provided by a TSA managed machine. The role handles:
- installation of dependency packages from Debian (optionally from the backports repository)
- formats additional volumes attached to the instance using the specified filesystem
- sets the timezone to UTC (Q: /is this what TSA do?/)
- creates user accounts for each member of the team
- all team members can perform unlimited passwordless sudo (TSA hosts require a password)
- SSH password authentication is disabled
- all user account passwords are removed/disabled
- creates service user accounts as specified
- home directories are created as specified, and linked from ~/home/$user~
- lingering is enabled for service users
This is all configured via group variables in the [[https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/group_vars][~ansible/group_vars/~]] folder. Examples there should help you to understand how
these work. These override the [[https://gitweb.torproject.org/metrics-cloud.git/tree/ansible/roles/metrics-common/defaults/main.yml][defaults]] set in the role.
** TODO Service roles
** DONE Linting
[[https://docs.ansible.com/ansible-lint/][~ansible-lint~]] is used to ensure we are complying with best practices. None of the team have formal training in the use of Ansible
so we are really making it up as we go along. Other tools may be used in the future, as we learn about them, to make sure we are using
things efficiently and correctly.
This is also run as part of the [[https://travis-ci.org/github/torproject/metrics-cloud/][continuous integration checks]] on Travis CI.
* TODO Common Tasks
** TODO Add a new member to the team
** TODO Update an SSH key for a team member
** TODO Deploy and provision a development environment for a service
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment