-
Notifications
You must be signed in to change notification settings - Fork 819
samples/guestbook: add sample application #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
7bedc38
137ad82
ad7433b
fb0d797
0146eb7
6c23658
9f6c32c
f329ef6
c1cd866
c6da8e9
827fc83
2bb9f57
644086c
dc9029d
feec1e4
c4fda21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# Guestbook Sample | ||
|
||
Guestbook is a sample application that records visitors' messages, displays a | ||
cloud banner, and an administrative message. The main business logic is | ||
written in a cloud-agnostic manner using MySQL, the generic blob API, and the | ||
generic runtimevar API. Each of the platform-specific code is set up by Wire. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "All platform-specific code" reads better to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
|
||
## Prerequisites | ||
|
||
You will need to install the following software to run this sample: | ||
|
||
- [Go](https://golang.org/doc/install) and | ||
[vgo](https://go.googlesource.com/vgo) | ||
- [Docker](https://docs.docker.com/install/) | ||
- [Terraform](https://www.terraform.io/intro/getting-started/install.html) | ||
- [jq](https://stedolan.github.io/jq/download/) | ||
- [gcloud CLI](https://cloud.google.com/sdk/downloads), if you want to use GCP | ||
- [aws CLI](https://docs.aws.amazon.com/cli/latest/userguide/installing.html), | ||
if you want to use AWS | ||
|
||
## Building | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. "You will need to install vgo with ... The vgo vendor step pulls down all required dependencies specified in go.mod" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
`gowire` is not compatible with `vgo` yet, so you must run `vgo vendor` | ||
first to download all the dependencies in `go.mod`. Running `gowire` | ||
generates the Wire code. | ||
|
||
```shell | ||
# First time, for gowire. | ||
$ vgo vendor | ||
|
||
# Now build: | ||
$ gowire && vgo build | ||
``` | ||
|
||
## Running Locally | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again a quick summary here would be nice. "You will need to run a MySQL database using Docker and then migrate that database. Then, you can start the app locally" or something similar. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
You will need to run a local MySQL database server using Docker, and then you | ||
can run the server. | ||
|
||
```shell | ||
./start-localdb.sh | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To avoid the pain of users forgetting to stop their container, you could make this a foregrounded process and tell the user to open a new session, tab, window, etc. |
||
./guestbook -env=local | ||
``` | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After it's all turned on, what do I do? What address do I visit in my browser? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
Stop the MySQL database server with: | ||
|
||
```shell | ||
$ docker stop guestbook-sql | ||
``` | ||
|
||
## Running on Google Cloud Platform (GCP) | ||
|
||
If you want to run this sample on GCP, you need to create a project, download | ||
the gcloud SDK, and log in. You can then use Terraform, a tool for | ||
initializing cloud resources, to set up your project. Finally, this sample | ||
provides a script for building the Guestbook binary and deploying it to the | ||
Kubernetes cluster created by Terraform. | ||
|
||
```shell | ||
gcloud auth application-default login | ||
cd gcp | ||
terraform init | ||
terraform apply | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Terraform prompts me for a project, a region, and a zone. Might be helpful to add a one-liner about what a user should enter to ease any friction. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's what I get when I follow this verbatim using my personal account on GCP:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this is hashicorp/terraform-provider-google#1579. I was getting it too and was about to start bothering folks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Granted, I know how to fix this myself by enabling the API (i.e., After running
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ironically, I believe these messages come up because the services are already enabled. :\ Tracking bug is hashicorp/terraform-provider-google#1579 |
||
./deploy.sh | ||
``` | ||
|
||
To clean up the created resources, run `terraform destroy` inside the `gcp` | ||
directory using the same variables you entered during `terraform apply`. | ||
|
||
## Running on Amazon Web Services (AWS) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. General comment: these two blocks (running on aws, running on gcp) are very dense. Could we add some comments about what some of the blocks are doing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Obsoleted by Terraform rewrite. |
||
|
||
If you want to run this sample on AWS, you need to set up an account, download | ||
the AWS command line interface, and log in. You can then use Terraform, a tool | ||
for initializing cloud resources, to set up your project. This will create an | ||
EC2 instance you can connect to and run your binary, copying over the | ||
configuration | ||
|
||
```shell | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. This should be moved into a script. The average user will be scared away otherwise. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a lazy software engineer, I would probably give up on this tutorial on seeing these commands honestly. This step should be made as easy as possible, e.g., export these environment variables and run the script. Also, although it might be obvious to someone who's been deep in the guts of GCP and AWS CLIs, the average user won't understand a lot of this stuff. So, once you move the commands into a script, add copious annotations explaining each step for the curious reader who wants to understand what you've asked them to do to their IaaS account. |
||
aws configure | ||
vgo build | ||
cd aws | ||
terraform init | ||
terraform apply -var region=us-west-1 | ||
|
||
# SSH into the EC2 instance. | ||
ssh "admin@$( terraform output instance_host )" | ||
``` | ||
|
||
When you're connected to the server, run the server binary. Replace the | ||
command-line flag values with values from the output of `terraform apply`. | ||
|
||
``` | ||
AWS_REGION=us-west-1 ./guestbook -env=aws \ | ||
-bucket=... -db_host=... -motd_var=... | ||
``` | ||
|
||
To clean up the created resources, run `terraform destroy` inside the `aws` | ||
directory using the same variables you entered during `terraform apply`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
# Copyright 2018 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# https://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
provider "aws" { | ||
version = "~> 1.22" | ||
region = "${var.region}" | ||
} | ||
|
||
provider "random" { | ||
version = "~> 1.3" | ||
} | ||
|
||
# Firewalls | ||
|
||
resource "aws_security_group" "guestbook" { | ||
name_prefix = "guestbook" | ||
description = "Sandbox for the Guestbook Go Cloud sample app." | ||
|
||
ingress { | ||
from_port = 22 | ||
to_port = 22 | ||
protocol = "tcp" | ||
cidr_blocks = ["0.0.0.0/0"] | ||
description = "Public SSH access" | ||
} | ||
|
||
ingress { | ||
from_port = 8080 | ||
to_port = 8080 | ||
protocol = "tcp" | ||
cidr_blocks = ["0.0.0.0/0"] | ||
description = "Public HTTP access" | ||
} | ||
|
||
ingress { | ||
from_port = 3306 | ||
to_port = 3306 | ||
protocol = "tcp" | ||
self = true | ||
description = "MySQL within group" | ||
} | ||
|
||
egress { | ||
from_port = 0 | ||
to_port = 0 | ||
protocol = "-1" | ||
cidr_blocks = ["0.0.0.0/0"] | ||
description = "All outgoing traffic allowed" | ||
} | ||
} | ||
|
||
# SQL Database (RDS) | ||
|
||
resource "random_string" "db_password" { | ||
special = false | ||
length = 20 | ||
} | ||
|
||
resource "aws_db_instance" "guestbook" { | ||
identifier_prefix = "guestbook" | ||
engine = "mysql" | ||
engine_version = "5.6.39" | ||
instance_class = "db.t2.micro" | ||
allocated_storage = 20 | ||
username = "root" | ||
password = "${random_string.db_password.result}" | ||
name = "guestbook" | ||
publicly_accessible = true | ||
vpc_security_group_ids = ["${aws_security_group.guestbook.id}"] | ||
skip_final_snapshot = true | ||
|
||
provisioner "local-exec" { | ||
# TODO(light): Reuse credentials from Terraform. | ||
command = "cat '${path.module}'/../schema.sql '${path.module}'/../roles.sql | '${path.module}'/provision-db.sh '${aws_db_instance.guestbook.address}' '${aws_security_group.guestbook.id}' guestbook '${random_string.db_password.result}'" | ||
} | ||
} | ||
|
||
# Blob Storage (S3) | ||
|
||
resource "aws_s3_bucket" "guestbook" { | ||
bucket_prefix = "guestbook" | ||
} | ||
|
||
# Paramstore (SSM) | ||
|
||
resource "aws_ssm_parameter" "motd" { | ||
name = "${var.paramstore_var}" | ||
type = "String" | ||
value = "ohai from AWS" | ||
} | ||
|
||
# Compute (EC2) | ||
|
||
resource "aws_iam_role" "guestbook" { | ||
name_prefix = "guestbook" | ||
|
||
assume_role_policy = <<EOF | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": { | ||
"Effect": "Allow", | ||
"Principal": {"Service": "ec2.amazonaws.com"}, | ||
"Action": "sts:AssumeRole" | ||
} | ||
} | ||
EOF | ||
} | ||
|
||
resource "aws_iam_role_policy" "guestbook" { | ||
name_prefix = "Guestbook-Policy" | ||
role = "${aws_iam_role.guestbook.id}" | ||
|
||
policy = <<EOF | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": { | ||
"Effect": "Allow", | ||
"Action": [ | ||
"s3:GetObject", | ||
"ssm:DescribeParameters", | ||
"ssm:GetParameter", | ||
"ssm:GetParameters", | ||
"xray:PutTraceSegments", | ||
"xray:PutTelemetryRecords" | ||
], | ||
"Resource": "*" | ||
} | ||
} | ||
EOF | ||
} | ||
|
||
resource "aws_iam_instance_profile" "guestbook" { | ||
name_prefix = "guestbook" | ||
role = "${aws_iam_role.guestbook.name}" | ||
} | ||
|
||
data "aws_ami" "debian" { | ||
most_recent = true | ||
|
||
filter { | ||
name = "product-code" | ||
values = ["55q52qvgjfpdj2fpfy9mb1lo4"] | ||
} | ||
|
||
filter { | ||
name = "product-code.type" | ||
values = ["marketplace"] | ||
} | ||
|
||
filter { | ||
name = "architecture" | ||
values = ["x86_64"] | ||
} | ||
|
||
owners = ["679593333241"] | ||
} | ||
|
||
resource "aws_key_pair" "guestbook" { | ||
key_name_prefix = "guestbook" | ||
public_key = "${var.ssh_public_key}" | ||
} | ||
|
||
resource "aws_instance" "guestbook" { | ||
ami = "${data.aws_ami.debian.id}" | ||
instance_type = "t2.micro" | ||
vpc_security_group_ids = ["${aws_security_group.guestbook.id}"] | ||
iam_instance_profile = "${aws_iam_instance_profile.guestbook.id}" | ||
key_name = "${aws_key_pair.guestbook.key_name}" | ||
|
||
connection { | ||
type = "ssh" | ||
user = "admin" | ||
} | ||
|
||
provisioner "file" { | ||
source = "${path.module}/../guestbook" | ||
destination = "/home/admin/guestbook" | ||
} | ||
|
||
provisioner "remote-exec" { | ||
inline = ["chmod +x /home/admin/guestbook"] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Copyright 2018 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# https://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
output "region" { | ||
value = "${var.region}" | ||
description = "Region the resources were created in." | ||
} | ||
|
||
output "bucket" { | ||
value = "${aws_s3_bucket.guestbook.id}" | ||
description = "Name of the S3 bucket created to store images." | ||
} | ||
|
||
output "database_host" { | ||
value = "${aws_db_instance.guestbook.address}" | ||
description = "Host name of the RDS MySQL database." | ||
} | ||
|
||
output "database_root_password" { | ||
value = "${random_string.db_password.result}" | ||
sensitive = true | ||
description = "Password for the root user of the RDS MySQL databse." | ||
} | ||
|
||
output "paramstore_var" { | ||
value = "${var.paramstore_var}" | ||
description = "Location of the SSM Parameter Store Message of the Day variable." | ||
} | ||
|
||
output "instance_host" { | ||
value = "${aws_instance.guestbook.public_ip}" | ||
description = "Address of the EC2 instance." | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have a few sentences summarizing what this sample does, e.g., "Guestbook is a sample application which records visitors' names. It also demonstrates a common (standard, conventional?) use of go-wire and go-cloud."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.