From b9a0f2ac5024832eeb335b2153cbc797a72caa83 Mon Sep 17 00:00:00 2001 From: Matthieu Werner Date: Wed, 29 Dec 2021 19:04:38 +0100 Subject: [PATCH] Add Docker provider Add AWS-Lambda provider --- .github/workflows/workflow.yaml | 35 ++ .gitignore | 7 + Makefile | 98 ++++ README.md | 487 ++++++++++++++++++ application/public/index.php | 3 + terraform/aws-lambda/main.tf | 19 + terraform/aws-lambda/output.tf | 15 + terraform/aws-lambda/resources.tf | 134 +++++ terraform/aws-lambda/variables.tf | 35 ++ terraform/aws-lambda/variables.tfvars | 6 + terraform/docker/images/builder/Dockerfile | 48 ++ .../docker/images/builder/etc/sudoers.d/sudo | 1 + .../mods-available/app-builder.ini | 5 + terraform/docker/images/frontend/Dockerfile | 25 + .../images/frontend/etc/nginx/environments | 0 .../images/frontend/etc/nginx/nginx.conf | 58 +++ .../images/frontend/etc/service/nginx/run | 3 + .../images/frontend/etc/service/php-fpm/run | 5 + .../php-configuration/fpm/php-fpm.conf | 18 + .../mods-available/app-fpm.ini | 5 + terraform/docker/images/php-base/Dockerfile | 43 ++ .../mods-available/app-default.ini | 27 + terraform/docker/images/postgres/Dockerfile | 3 + terraform/docker/images/router/Dockerfile | 3 + .../images/router/etc/ssl/certs/cert.pem | 31 ++ .../images/router/etc/ssl/certs/key.pem | 52 ++ .../router/etc/traefik/dynamic_conf.yaml | 12 + .../images/router/etc/traefik/traefik.yaml | 28 + .../docker/images/router/generate-ssl.sh | 17 + terraform/docker/images/router/openssl.cnf | 19 + terraform/docker/images/worker/Dockerfile | 9 + terraform/docker/images/worker/entrypoint.sh | 9 + terraform/docker/main.tf | 19 + terraform/docker/output.tf | 10 + terraform/docker/resources.tf | 121 +++++ terraform/docker/variables.tf | 28 + terraform/docker/variables.tfvars | 2 + 37 files changed, 1440 insertions(+) create mode 100644 .github/workflows/workflow.yaml create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 application/public/index.php create mode 100644 terraform/aws-lambda/main.tf create mode 100644 terraform/aws-lambda/output.tf create mode 100644 terraform/aws-lambda/resources.tf create mode 100644 terraform/aws-lambda/variables.tf create mode 100644 terraform/aws-lambda/variables.tfvars create mode 100644 terraform/docker/images/builder/Dockerfile create mode 100644 terraform/docker/images/builder/etc/sudoers.d/sudo create mode 100644 terraform/docker/images/builder/php-configuration/mods-available/app-builder.ini create mode 100644 terraform/docker/images/frontend/Dockerfile create mode 100644 terraform/docker/images/frontend/etc/nginx/environments create mode 100644 terraform/docker/images/frontend/etc/nginx/nginx.conf create mode 100755 terraform/docker/images/frontend/etc/service/nginx/run create mode 100755 terraform/docker/images/frontend/etc/service/php-fpm/run create mode 100644 terraform/docker/images/frontend/php-configuration/fpm/php-fpm.conf create mode 100644 terraform/docker/images/frontend/php-configuration/mods-available/app-fpm.ini create mode 100644 terraform/docker/images/php-base/Dockerfile create mode 100644 terraform/docker/images/php-base/php-configuration/mods-available/app-default.ini create mode 100644 terraform/docker/images/postgres/Dockerfile create mode 100644 terraform/docker/images/router/Dockerfile create mode 100644 terraform/docker/images/router/etc/ssl/certs/cert.pem create mode 100644 terraform/docker/images/router/etc/ssl/certs/key.pem create mode 100644 terraform/docker/images/router/etc/traefik/dynamic_conf.yaml create mode 100644 terraform/docker/images/router/etc/traefik/traefik.yaml create mode 100644 terraform/docker/images/router/generate-ssl.sh create mode 100644 terraform/docker/images/router/openssl.cnf create mode 100644 terraform/docker/images/worker/Dockerfile create mode 100644 terraform/docker/images/worker/entrypoint.sh create mode 100644 terraform/docker/main.tf create mode 100644 terraform/docker/output.tf create mode 100644 terraform/docker/resources.tf create mode 100644 terraform/docker/variables.tf create mode 100644 terraform/docker/variables.tfvars diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml new file mode 100644 index 0000000..56c2e81 --- /dev/null +++ b/.github/workflows/workflow.yaml @@ -0,0 +1,35 @@ +name: tf-starter tests suite +on: [push] +jobs: + tf-starter-tests-suite: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + + - name: Cache tools + id: cache-tools + uses: actions/cache@v2 + with: + path: tools + key: tools + + - name: Terraform lint + run: terraform fmt -check -recursive + + - name: Download Tools + if: steps.cache-tools.outputs.cache-hit != 'true' + run: | + mkdir -p tools + curl -sSL /~https://github.com/phpstan/phpstan/releases/download/1.3.3/phpstan.phar -o tools/phpstan + chmod a+x tools/phpstan + curl -L https://cs.symfony.com/download/php-cs-fixer-v3.phar -o tools/php-cs-fixer + chmod a+x tools/php-cs-fixer + + - name: PHPStan analyze + run: | + tools/phpstan analyze --level=max application + + - name: CS Check + run: | + tools/php-cs-fixer fix application --rules=@PhpCsFixer,@PHP81Migration --diff --no-interaction --dry-run diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6394a30 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.idea/ +*.terraform/ +*.build/ +*vendor/ +*.tfstate +*.lock.hcl +*.backup \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a830d56 --- /dev/null +++ b/Makefile @@ -0,0 +1,98 @@ + +# !! Set here your project configuration !! +export TF_VAR_project_name=terraform +export TF_VAR_project_domain=terraform.test +export TF_VAR_php_version=8.1 + +# Commands +TERRAFORM?=DOCKER_BUILDKIT=1 terraform +TERRAFORM_FOLDER = terraform +DOCKER_EXEC?=docker exec -it -u app +DOCKER_RUN?=docker run -it -u app --rm +BUILDER?=$(DOCKER_RUN) -v "${PWD}:/home/app/application" \ + -v "${COMPOSER_CACHE_DIR}:/home/app/.composer/cache" \ + -v "builder-data:/home/app" \ + builder + +# Help command +.DEFAULT_GOAL := help +.PHONY: help +help: ## Display commands list + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[$$()% 0-9a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +## Local stack: +start: ## Build & start containers + terraform -chdir=$(TERRAFORM_FOLDER)/docker init -var-file=variables.tfvars + terraform -chdir=$(TERRAFORM_FOLDER)/docker apply -var-file=variables.tfvars -auto-approve + +stop: ## Stop containers + docker stop $$(docker container ls -q --filter name=$(TF_VAR_project_name)) + +restart: ## Restart containers + docker restart $$(docker container ls -q --filter name=$(TF_VAR_project_name)) + +builder: ## Start terminal on the "builder" container as "app" + $(BUILDER) /bin/bash + +logs: ## Show local logs + docker ps -q | xargs -L 1 docker logs + +reset: destroy start ## Destroy images and containers and restart the stack + +destroy: ## Destroy images and containers + terraform -chdir=$(TERRAFORM_FOLDER)/docker destroy -auto-approve + +## Project specific: +install: ## Install dependencies. + $(BUILDER) composer --working-dir=application install + +optimize: ## Optimize dependencies for production. + rm -rf vendor + $(BUILDER) composer --working-dir=application install --prefer-dist --optimize-autoloader --no-dev + +update: ## Update dependencies. + $(BUILDER) composer --working-dir=application update + +cs_fix: + $(BUILDER) php-cs-fixer fix application --rules=@PhpCsFixer,@PHP81Migration --diff --no-interaction + +## Provider: AWS - Lambda +lambda-deploy: ## Deploy application in a AWS Lambda environment . + terraform -chdir=$(TERRAFORM_FOLDER)/aws init -var-file=variables.tfvars -reconfigure -upgrade + terraform -chdir=$(TERRAFORM_FOLDER)/aws apply -var-file=variables.tfvars + +lambda-get-url: ## Get URL of the Lambda. + terraform -chdir=$(TERRAFORM_FOLDER)/aws output -raw base_url + +lambda-show-bucket: ## Show the Lambda bucket content. + aws s3 ls $(terraform output -raw lambda_bucket_name) + +## Installers: +install-symfony: ## Install Symfony + $(BUILDER) mv application application.old + $(BUILDER) composer create-project --no-interaction --verbose symfony/website-skeleton application "^5.4" + $(BUILDER) composer require --working-dir=application --no-interaction "bref/bref" "bref/extra-php-extensions" "bref/symfony-bridge" + $(BUILDER) sed -i 's#DATABASE_URL.*#DATABASE_URL=postgresql://app:app@postgres:5432/app\?serverVersion=12\&charset=utf8#' application/.env + $(MAKE) restart + +install-apip: ## Install API Platform + $(BUILDER) mv application application.old + $(BUILDER) composer create-project --no-interaction --verbose symfony/website-skeleton application "^5.4" + $(BUILDER) composer require --working-dir=application --no-interaction "api" "bref/bref" "bref/extra-php-extensions" "bref/symfony-bridge" + $(MAKE) restart + +install-laravel: ## Install Laravel + $(BUILDER) mv application application.old + $(BUILDER) composer create-project --no-interaction --verbose laravel/laravel application + $(BUILDER) composer require --working-dir=application --no-interaction "bref/bref" "bref/extra-php-extensions" "bref/laravel-bridge" + $(MAKE) restart + +## Tests: +terraform-lint: ## Check Terraform syntax + terraform fmt -check -recursive + +cs_check: + $(BUILDER) php-cs-fixer fix application --rules=@PhpCsFixer,@PHP81Migration --diff --no-interaction --dry-run + +phpstan: + $(BUILDER) phpstan analyze --level=max application diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ae2ad3 --- /dev/null +++ b/README.md @@ -0,0 +1,487 @@ +[![tf-starter tests suite](/~https://github.com/matthieuwerner/tf-starter/actions/workflows/workflow.yaml/badge.svg)](/~https://github.com/matthieuwerner/tf-starter/actions/workflows/workflow.yaml) + +## Introduction + +This project has been created to bootstrap your PHP project (Symfony, Laravel, Api Platform, or whatever ...) with Terraform. + +Install dependencies and run the **start** command **to have a full PHP stack running locally** 🥳. +Local configuration is described via the [Docker provider](https://registry.terraform.io/providers/kreuzwerker/docker/latest/docs) +in the **terraform/docker** directory. + +After that, just run **deploy-[provider]** command to build your stack on your favorite provider. +AWS-Lambda is for now the only available provider. + +This project compile stuff from [JoliCode Docker Starter](/~https://github.com/jolicode/docker-starter), + [Bref.sh](https://bref.sh/) layers and [Terraform learning resources](https://learn.hashicorp.com/terraform). + +😎 **Pssst: Use this project as a Github template** + +## Quickstart 🚄 + +Install the following dependencies: +- [Docker](https://docs.docker.com/get-docker/) +- [Terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli) +- [make](https://en.wikipedia.org/wiki/Make_(software)) + +Replace variables in `Makefle`: +```Makefile +export TF_VAR_project_name=terraform +export TF_VAR_project_domain=terraform.test +export TF_VAR_php_version=8.1 +``` + +You can additionally add context or custom variables in your `terraform/docker/variables.tfvars`: +```terraform +env = { # Environnement variables + APP_NAME = "tf-starter" + APP_DEBUG = true + APP_ENV = "prod" +} +``` + +Replace variables in `terraform/docker/variables.tfvars`: +```terraform +project_name = "terraform" # Your project name, used as a prefix of images and containers +project_domain = "terraform.test" # The local domain +php_version = "8.1" # The PHP version to use + +env = { # Environnement variables + APP_NAME = "tf-starter" + APP_DEBUG = true + APP_ENV = "prod" +} +``` + +Configure your local host in the **/etc/hosts** file: +``` +# Use the same domain as "project_domain" in the previous block +echo "127.0.0.1 terraform.test www.terraform.test" >> /etc/hosts +``` + +_You optionally can install your favorite framework with [installers](#installers):_ +```bash +make install-symfony +``` + +Start the local stack: +``` +make start +``` + +Go to your `project_domain`, you should now see your website content. + +To configure deployment, you now have to read the appropriate section: +- [AWS - Lambda](#AWS---Lambda) + +## Providers + +### AWS - Lambda + +AWS Lambda provider use Bref.sh layers on top of AWS Lambda. + +#### Quickstart + +Replace or add variables in `terraform/aws/variables.tfvars` if needed: +```terraform +env = { + DEFAULT_REGION = "eu-west-3" + APP_NAME = "tf-starter" + APP_DEBUG = true + APP_ENV = "prod" +} +``` + +Deploy your application: +``` +make lambda-deploy +``` + +This will output something like : + +```bash +Apply complete! Resources: x added, x changed, x destroyed. + +Outputs: + +base_url = "https://**********.execute-api.eu-west-3.amazonaws.com/" +function_name = "terraform" +lambda_bucket_name = "terraform-dev" +``` + +Go to the provided **base_url**, you should now see an : +``` +Hello world! +``` + +#### Variables + +`project_name`: Project name used as function name. + +`php_layer`: Bref.sh layer arn for your PHP version. The layer have to be in the same region +as your lambda. You will find a complete list here: https://bref.sh/docs/runtimes/index.html#lambda-layers-in-details + +`entrypoint`: The entrypoint of your script. Default is `public/index.php`. + +`aws_region`: AWS region. Default is `eu-west-3`. + +`aws_profile`: AWS profile. Default is `default`. + +`env`: Environment variables as an object. Ex: `{FOO = "BAR"}` + +## Cookbook 🤠 + +To go further ... (and you will) + +### Installers + +Use **installers** to initialize the `application` folder with your favorite framework. + +*⚠ It will clear the "application" folder content, and backup the old one with .old exentension.* + +#### Install Symfony + +```bash +make install-symfony +``` + +Continue the magic with the [maker bundle](https://symfony.com/bundles/SymfonyMakerBundle/current/index.html). +Example: +```bash +make builder +cd application +bin/console make:controller +``` + +#### Install API Platform + +```bash +make install-apip +``` + +#### Install Laravel + +```bash +make install-laravel +``` + +### Add more services + +
+Elasticsearch + +#### Local stack + +Add the following code to `terraform/docker/resources.tf`: +```terraform +// Elasticsearch -------------------------------- +resource "docker_image" "elasticsearch" { + name = "elasticsearch:7.16.2" +} + +resource "docker_container" "elasticsearch" { + name = "${var.project_name}_elasticsearch" + image = docker_image.elasticsearch.latest + network_mode = "tf-starter_network" + env = ["discovery.type=single-node"] + volumes { + volume_name = "elasticsearch-data" + container_path = "/usr/share/elasticsearch/data" + } + labels { + label = "traefik.enable" + value = "true" + } + labels { + label = "traefik.http.routers.${var.project_name}-elasticsearch.rule" + value = "Host(`elasticsearch.${var.project_domain}`)" + } + labels { + label = "traefik.http.routers.${var.project_name}-elasticsearch.tls" + value = "true" + } +} + +resource "docker_image" "kibana" { + name = "kibana:7.16.2" +} + +resource "docker_container" "kibana" { + name = "${var.project_name}_kibana" + image = docker_image.kibana.latest + depends_on = [docker_container.elasticsearch] + network_mode = "tf-starter_network" + labels { + label = "traefik.enable" + value = "true" + } + labels { + label = "traefik.http.routers.${var.project_name}-kibana.rule" + value = "Host(`kibana.${var.project_domain}`)" + } + labels { + label = "traefik.http.routers.${var.project_name}-kibana.tls" + value = "true" + } +} +``` + +Add the following code to `terraform/docker/output.tf`: +```terraform +output "Elasticsearch" { + description = "Elasticsearch informations" + value="https://elasticsearch.${var.project_domain}" +} + +output "Kibana" { + description = "Elasticsearch informations" + value="https://kibana.${var.project_domain}" +} +``` + +#### Provider: AWS Lambda + +Add the following code to `terraform/aws-lambda/resources.tf`: +```terraform +resource "aws_elasticsearch_domain" "es" { + domain_name = local.elk_domain + elasticsearch_version = "7.7" + + cluster_config { + instance_count = 3 + instance_type = "r5.large.elasticsearch" + zone_awareness_enabled = true + + zone_awareness_config { + availability_zone_count = 3 + } + } + + vpc_options { + subnet_ids = [ + aws_subnet.nated_1.id, + aws_subnet.nated_2.id, + aws_subnet.nated_3.id + ] + + security_group_ids = [ + aws_security_group.es.id + ] + } + + ebs_options { + ebs_enabled = true + volume_size = 10 + } + + access_policies = < + +
+Redis + +#### Local stack + +Add the following code to `terraform/docker/resources.tf`: +```terraform +// Redis -------------------------------- +resource "docker_image" "redis" { + name = "redis:6.2" +} + +resource "docker_container" "redis" { + name = "${var.project_name}_redis" + image = docker_image.redis.latest + network_mode = "tf-starter_network" + volumes { + volume_name = "redis-data" + container_path = "/data" + } +} + +resource "docker_image" "redis-insight" { + name = "redislabs/redisinsight" +} + +resource "docker_container" "redis-insight" { + name = "${var.project_name}_redis_insight" + image = docker_image.redis-insight.latest + depends_on = [docker_container.redis] + network_mode = "tf-starter_network" + volumes { + volume_name = "redis-insight-data" + container_path = "/db" + } + labels { + label = "traefik.enable" + value = "true" + } + labels { + label = "traefik.http.routers.${var.project_name}-redis.rule" + value = "Host(`redis.${var.project_domain}`)" + } + labels { + label = "traefik.http.routers.${var.project_name}-redis.tls" + value = "true" + } +} +``` + +Add the following code to `terraform/docker/output.tf`: +```terraform +output "Redis" { + description = "Redis informations" + value="https://redis.${var.project_domain}" +} +``` + +#### Provider: AWS Lambda + +Add the following layer (match layer-version and region with https://raw.githubusercontent.com/brefphp/extra-php-extensions/master/layers.json): + +```terraform +arn:aws:lambda::403367587399:layer:redis-php-81: + +# ex: arn:aws:lambda:eu-west-3:403367587399:layer:redis-php-81:4 +``` + +
+ +
+RabbitMQ + +#### Local stack + +Add the following code to `terraform/docker/resources.tf`: +```terraform +// RabbitMQ -------------------------------- +resource "docker_image" "rabbitmq" { + name = "rabbitmq:3.9-management-alpine" +} + +resource "docker_container" "rabbitmq" { + name = "${var.project_name}_redis_insight" + image = docker_image.rabbitmq.latest + network_mode = "tf-starter_network" + env = ["RABBITMQ_VM_MEMORY_HIGH_WATERMARK=1024MiB"] + volumes { + volume_name = "rabbitmq-data" + container_path = "/var/lib/rabbitmq" + } + labels { + label = "traefik.enable" + value = "true" + } + labels { + label = "traefik.http.routers.${var.project_name}-rabbitmq.rule" + value = "Host(`rabbitmq.${var.project_domain}`)" + } + labels { + label = "traefik.http.routers.${var.project_name}-rabbitmq.tls" + value = "true" + } + labels { + label = "traefik.http.services.rabbitmq.loadbalancer.server.port" + value = "15672" + } +} +``` + +Add the following code to `terraform/docker/output.tf`: +```terraform +output "Rabbitmq" { + description = "Rabbitmq informations" + value="https://rabbitmq.${var.project_domain}" +} +``` + +#### Provider: AWS Lambda + +Add the following layer (match layer-version and region with https://raw.githubusercontent.com/brefphp/extra-php-extensions/master/layers.json): + +```terraform +arn:aws:lambda::403367587399:layer:amqp-php-80: + +# ex: arn:aws:lambda:eu-west-3:403367587399:layer:amqp-php-80:4 +``` + +
+ +### Manage environments + +There are a lot a way to deal with multiple environments like preprod or prod. +If your stack are basically similar between environments, you could create one [workspace](https://www.terraform.io/language/state/workspaces) +for each. + +```bash +# Create a preprod workspace +terraform workspace new preprod + +# Create a prod workspace +terraform workspace new prod + +# List workspaces +terraform workspace list +``` + +After that, create in your provider working directory an `environment` folder with +2 tfvars files, named as your workspaces. +(`ex: aws-lambda/environment/preprod.tfvars.`). + +Edit your Makefile commands for chosen provider and replace ` -var-file=variables.tfvars` by +`-var-file=environment/$$(terraform workspace show).tfvars`. + +Now you juste have to adapt your .tfvars files by environment, and navigate +between your workspaces with: +```bash +# To use "prod" environment +terraform workspace select prod +``` + +Your commands will now automatically use the variable configuration who match the current workspace 🙌🏻. + +### Cleanup the mess + +After initialization, you can (should) safely remove useless providers, installer commands, replace the readme, etc. + +--- +``` +Usefull stuff used in this repo (thanks to them): +- Docker starter: /~https://github.com/jolicode/docker-starter +- Bref.sh: https://bref.sh/ +- TF learning respources: https://learn.hashicorp.com/terraform +- Makefile tips: https://gist.github.com/prwhite/8168133?permalink_comment_id=3785627#gistcomment-3785627 +``` \ No newline at end of file diff --git a/application/public/index.php b/application/public/index.php new file mode 100644 index 0000000..297fbe7 --- /dev/null +++ b/application/public/index.php @@ -0,0 +1,3 @@ + 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 3.48.0" + } + archive = { + source = "hashicorp/archive" + version = "~> 2.2.0" + } + } +} + +provider "aws" { + region = var.aws_region + profile = var.aws_profile +} diff --git a/terraform/aws-lambda/output.tf b/terraform/aws-lambda/output.tf new file mode 100644 index 0000000..63a1a67 --- /dev/null +++ b/terraform/aws-lambda/output.tf @@ -0,0 +1,15 @@ + +output "lambda_bucket_name" { + description = "Name of the S3 bucket used to store function code." + value = aws_s3_bucket.lambda_bucket.id +} + +output "function_name" { + description = "Name of the Lambda function." + value = aws_lambda_function.application.function_name +} + +output "base_url" { + description = "Base URL for API Gateway stage." + value = aws_apigatewayv2_stage.lambda.invoke_url +} diff --git a/terraform/aws-lambda/resources.tf b/terraform/aws-lambda/resources.tf new file mode 100644 index 0000000..fd23bc7 --- /dev/null +++ b/terraform/aws-lambda/resources.tf @@ -0,0 +1,134 @@ + +// S3 deployment +resource "aws_s3_bucket" "lambda_bucket" { + bucket = "${var.project_name}-${terraform.workspace}" + + acl = "private" + force_destroy = true +} + +// Package application +data "archive_file" "lambda_application" { + type = "zip" + source_dir = "${path.module}/../../application" + output_path = "${path.module}/.build/${var.project_name}.zip" + +} + +resource "aws_s3_bucket_object" "lambda_application" { + bucket = aws_s3_bucket.lambda_bucket.id + key = "${var.project_name}.zip" + source = data.archive_file.lambda_application.output_path + etag = filemd5(data.archive_file.lambda_application.output_path) +} + +// Lambda function definition +resource "aws_lambda_function" "application" { + function_name = var.project_name + + s3_bucket = aws_s3_bucket.lambda_bucket.id + s3_key = aws_s3_bucket_object.lambda_application.key + + runtime = "provided.al2" + layers = [var.php_layer] + handler = var.entrypoint + memory_size = 1024 + timeout = 28 + + source_code_hash = data.archive_file.lambda_application.output_base64sha256 + + role = aws_iam_role.lambda_exec.arn + + environment { + variables = var.env + } +} + +resource "aws_cloudwatch_log_group" "application" { + name = "/aws/lambda/${aws_lambda_function.application.function_name}" + + retention_in_days = 30 +} + +resource "aws_iam_role" "lambda_exec" { + name = "serverless_lambda" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Sid = "" + Principal = { + Service = "lambda.amazonaws.com" + } + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "lambda_policy" { + role = aws_iam_role.lambda_exec.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" +} + +// Api gateway +resource "aws_apigatewayv2_api" "lambda" { + name = "serverless_lambda_gw" + protocol_type = "HTTP" +} + +resource "aws_apigatewayv2_stage" "lambda" { + api_id = aws_apigatewayv2_api.lambda.id + + name = "$default" + auto_deploy = true + + access_log_settings { + destination_arn = aws_cloudwatch_log_group.api_gw.arn + + format = jsonencode({ + requestId = "$context.requestId" + sourceIp = "$context.identity.sourceIp" + requestTime = "$context.requestTime" + protocol = "$context.protocol" + httpMethod = "$context.httpMethod" + resourcePath = "$context.resourcePath" + routeKey = "$context.routeKey" + status = "$context.status" + responseLength = "$context.responseLength" + integrationErrorMessage = "$context.integrationErrorMessage" + } + ) + } +} + +resource "aws_apigatewayv2_integration" "application" { + api_id = aws_apigatewayv2_api.lambda.id + + integration_uri = aws_lambda_function.application.invoke_arn + integration_type = "AWS_PROXY" + integration_method = "POST" +} + +resource "aws_apigatewayv2_route" "application" { + api_id = aws_apigatewayv2_api.lambda.id + + route_key = "$default" + target = "integrations/${aws_apigatewayv2_integration.application.id}" +} + +resource "aws_cloudwatch_log_group" "api_gw" { + name = "/aws/api_gw/${aws_apigatewayv2_api.lambda.name}" + + retention_in_days = 30 +} + +resource "aws_lambda_permission" "api_gw" { + statement_id = "AllowExecutionFromAPIGateway" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.application.function_name + principal = "apigateway.amazonaws.com" + + source_arn = "${aws_apigatewayv2_api.lambda.execution_arn}/*/*" +} diff --git a/terraform/aws-lambda/variables.tf b/terraform/aws-lambda/variables.tf new file mode 100644 index 0000000..94efb6f --- /dev/null +++ b/terraform/aws-lambda/variables.tf @@ -0,0 +1,35 @@ +variable "project_name" { + description = "Project name used as function name." + type = string + default = "tf-starter" +} + +variable "php_layer" { + description = "PHP layer for your version." + type = string + default = "arn:aws:lambda:eu-west-3:209497400698:layer:php-81-fpm:16" +} + +variable "entrypoint" { + description = "Bref.sh PHP handler." + type = string + default = "public/index.php" +} + +variable "aws_region" { + description = "AWS region for all resources." + type = string + default = "eu-west-3" +} + +variable "aws_profile" { + description = "AWS profile." + type = string + default = "default" +} + +variable "env" { + description = "Environnement variables." + type = map(any) + default = {} +} diff --git a/terraform/aws-lambda/variables.tfvars b/terraform/aws-lambda/variables.tfvars new file mode 100644 index 0000000..7c1b7f5 --- /dev/null +++ b/terraform/aws-lambda/variables.tfvars @@ -0,0 +1,6 @@ +env = { + DEFAULT_REGION = "eu-west-3" + APP_NAME = "tf-starter" + APP_DEBUG = true + APP_ENV = "prod" +} \ No newline at end of file diff --git a/terraform/docker/images/builder/Dockerfile b/terraform/docker/images/builder/Dockerfile new file mode 100644 index 0000000..b6475b6 --- /dev/null +++ b/terraform/docker/images/builder/Dockerfile @@ -0,0 +1,48 @@ +ARG PROJECT_NAME + +FROM php-base + +ARG NODEJS_VERSION=14.x +RUN echo "deb https://deb.nodesource.com/node_${NODEJS_VERSION} buster main" > /etc/apt/sources.list.d/nodejs.list \ + && apt-key adv --fetch-keys https://deb.nodesource.com/gpgkey/nodesource.gpg.key + +# Default toys +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + curl \ + git \ + make \ + nodejs \ + sudo \ + unzip \ + && apt-get clean \ + && npm install -g yarn \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* + +# Config +COPY etc/. /etc/ +ARG PHP_VERSION +COPY php-configuration /etc/php/${PHP_VERSION} +RUN adduser app sudo \ + && mkdir /var/log/php \ + && chmod 777 /var/log/php \ + && phpenmod app-default \ + && phpenmod app-builder + +# Composer +COPY --from=composer/composer:2.1.6 /usr/bin/composer /usr/bin/composer +RUN mkdir -p "/home/app/.composer/cache" \ + && chown app: /home/app/.composer -R + +# PHPStan +RUN curl -sSL /~https://github.com/phpstan/phpstan/releases/download/1.3.3/phpstan.phar -o phpstan \ + && chmod a+x phpstan \ + && mv phpstan /usr/local/bin/phpstan + +# CSFixer +RUN curl -L https://cs.symfony.com/download/php-cs-fixer-v3.phar -o php-cs-fixer \ + && chmod a+x php-cs-fixer \ + && mv php-cs-fixer /usr/local/bin/php-cs-fixer + + +WORKDIR /home/app/application diff --git a/terraform/docker/images/builder/etc/sudoers.d/sudo b/terraform/docker/images/builder/etc/sudoers.d/sudo new file mode 100644 index 0000000..b835421 --- /dev/null +++ b/terraform/docker/images/builder/etc/sudoers.d/sudo @@ -0,0 +1 @@ +%sudo ALL=(ALL) NOPASSWD: ALL diff --git a/terraform/docker/images/builder/php-configuration/mods-available/app-builder.ini b/terraform/docker/images/builder/php-configuration/mods-available/app-builder.ini new file mode 100644 index 0000000..3016083 --- /dev/null +++ b/terraform/docker/images/builder/php-configuration/mods-available/app-builder.ini @@ -0,0 +1,5 @@ +; priority=40 +[PHP] +error_log = /var/log/php/error.log +[opcache] +opcache.error_log = /var/log/php/opcache.log diff --git a/terraform/docker/images/frontend/Dockerfile b/terraform/docker/images/frontend/Dockerfile new file mode 100644 index 0000000..c13428f --- /dev/null +++ b/terraform/docker/images/frontend/Dockerfile @@ -0,0 +1,25 @@ +ARG PROJECT_NAME + +FROM php-base + +ARG PHP_VERSION + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + nginx \ + php${PHP_VERSION}-fpm \ + runit \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* + +RUN useradd -s /bin/false nginx + +COPY etc/. /etc/ +COPY php-configuration /etc/php/${PHP_VERSION} + +RUN phpenmod app-default \ + && phpenmod app-fpm + +EXPOSE 80 + +CMD ["runsvdir", "-P", "/etc/service"] diff --git a/terraform/docker/images/frontend/etc/nginx/environments b/terraform/docker/images/frontend/etc/nginx/environments new file mode 100644 index 0000000..e69de29 diff --git a/terraform/docker/images/frontend/etc/nginx/nginx.conf b/terraform/docker/images/frontend/etc/nginx/nginx.conf new file mode 100644 index 0000000..5f5e458 --- /dev/null +++ b/terraform/docker/images/frontend/etc/nginx/nginx.conf @@ -0,0 +1,58 @@ +user nginx; +pid /var/run/nginx.pid; +daemon off; +error_log /proc/self/fd/2; + +http { + access_log /proc/self/fd/1; + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + include /etc/nginx/mime.types; + default_type application/octet-stream; + client_max_body_size 20m; + server_tokens off; + + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; + + server { + listen 0.0.0.0:80; + root /home/app/application/public; + + location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ { + access_log off; + add_header Cache-Control "no-cache"; + } + + location / { + # try to serve file directly, fallback to index.php + try_files $uri /index.php$is_args$args; + } + + location ~ ^/index\.php(/|$) { + fastcgi_pass 127.0.0.1:9000; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + + include fastcgi_params; + include environments; + + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTPS on; + fastcgi_param SERVER_NAME $http_host; + } + + error_log /proc/self/fd/2; + access_log /proc/self/fd/1; + } +} + +events {} diff --git a/terraform/docker/images/frontend/etc/service/nginx/run b/terraform/docker/images/frontend/etc/service/nginx/run new file mode 100755 index 0000000..14cd019 --- /dev/null +++ b/terraform/docker/images/frontend/etc/service/nginx/run @@ -0,0 +1,3 @@ +#!/bin/sh + +exec /usr/sbin/nginx diff --git a/terraform/docker/images/frontend/etc/service/php-fpm/run b/terraform/docker/images/frontend/etc/service/php-fpm/run new file mode 100755 index 0000000..b73a435 --- /dev/null +++ b/terraform/docker/images/frontend/etc/service/php-fpm/run @@ -0,0 +1,5 @@ +#!/bin/sh + +PHP_VERSION=$(php -r 'printf("%s.%s", PHP_MAJOR_VERSION, PHP_MINOR_VERSION);') + +exec /usr/sbin/php-fpm$PHP_VERSION -y /etc/php/$PHP_VERSION/fpm/php-fpm.conf -O diff --git a/terraform/docker/images/frontend/php-configuration/fpm/php-fpm.conf b/terraform/docker/images/frontend/php-configuration/fpm/php-fpm.conf new file mode 100644 index 0000000..2360969 --- /dev/null +++ b/terraform/docker/images/frontend/php-configuration/fpm/php-fpm.conf @@ -0,0 +1,18 @@ +[global] +pid = /var/run/php-fpm.pid +error_log = /proc/self/fd/2 +daemonize = no + +[www] +user = app +group = app +listen = 127.0.0.1:9000 +pm = dynamic +pm.max_children = 4 +pm.start_servers = 2 +pm.min_spare_servers = 2 +pm.max_spare_servers = 3 +pm.max_requests = 500 +clear_env = no +request_terminate_timeout = 120s +catch_workers_output = yes diff --git a/terraform/docker/images/frontend/php-configuration/mods-available/app-fpm.ini b/terraform/docker/images/frontend/php-configuration/mods-available/app-fpm.ini new file mode 100644 index 0000000..f3f541d --- /dev/null +++ b/terraform/docker/images/frontend/php-configuration/mods-available/app-fpm.ini @@ -0,0 +1,5 @@ +; priority=40 +[PHP] +expose_php = off +memory_limit = 128M +max_execution_time = 30 diff --git a/terraform/docker/images/php-base/Dockerfile b/terraform/docker/images/php-base/Dockerfile new file mode 100644 index 0000000..f41030a --- /dev/null +++ b/terraform/docker/images/php-base/Dockerfile @@ -0,0 +1,43 @@ +FROM debian:10.9-slim + +RUN apt-get update \ + && apt install -y --no-install-recommends \ + ca-certificates \ + gnupg \ + && echo "deb https://packages.sury.org/php buster main" > /etc/apt/sources.list.d/sury.list \ + && apt-key adv --fetch-keys https://packages.sury.org/php/apt.gpg + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + procps \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* + +ARG PHP_VERSION + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + php${PHP_VERSION}-apcu \ + php${PHP_VERSION}-bcmath \ + php${PHP_VERSION}-cli \ + php${PHP_VERSION}-common \ + php${PHP_VERSION}-curl \ + php${PHP_VERSION}-fpm \ + php${PHP_VERSION}-iconv \ + php${PHP_VERSION}-intl \ + php${PHP_VERSION}-mbstring \ + php${PHP_VERSION}-pgsql \ + php${PHP_VERSION}-uuid \ + php${PHP_VERSION}-xml \ + php${PHP_VERSION}-zip \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* + +# Fake user to maps with the one on the host +ARG USER_ID=1000 +ARG GROUP_ID=1000 +RUN addgroup --gid $GROUP_ID app && \ + adduser --system --uid $USER_ID --home /home/app --shell /bin/bash app + +# Configuration +COPY php-configuration /etc/php/${PHP_VERSION} diff --git a/terraform/docker/images/php-base/php-configuration/mods-available/app-default.ini b/terraform/docker/images/php-base/php-configuration/mods-available/app-default.ini new file mode 100644 index 0000000..17d01e4 --- /dev/null +++ b/terraform/docker/images/php-base/php-configuration/mods-available/app-default.ini @@ -0,0 +1,27 @@ +; priority=30 +[PHP] +short_open_tag = Off +memory_limit = 512M +error_reporting = E_ALL +display_errors = On +display_startup_errors = On +error_log = /proc/self/fd/2 +log_errors = On +log_errors_max_len = 0 +max_execution_time = 0 +always_populate_raw_post_data = -1 +upload_max_filesize = 20M +post_max_size = 20M +[Date] +date.timezone = UTC +[Phar] +phar.readonly = Off +[opcache] +opcache.memory_consumption=256 +opcache.max_accelerated_files=20000 +realpath_cache_size=4096K +realpath_cache_ttl=600 +opcache.error_log = /proc/self/fd/2 +[apc] +apc.enabled=1 +apc.enable_cli=1 diff --git a/terraform/docker/images/postgres/Dockerfile b/terraform/docker/images/postgres/Dockerfile new file mode 100644 index 0000000..dec53c0 --- /dev/null +++ b/terraform/docker/images/postgres/Dockerfile @@ -0,0 +1,3 @@ +FROM postgres:12 + +EXPOSE 5432 diff --git a/terraform/docker/images/router/Dockerfile b/terraform/docker/images/router/Dockerfile new file mode 100644 index 0000000..3f31bc6 --- /dev/null +++ b/terraform/docker/images/router/Dockerfile @@ -0,0 +1,3 @@ +FROM traefik:v2.2 + +COPY etc/. /etc/ diff --git a/terraform/docker/images/router/etc/ssl/certs/cert.pem b/terraform/docker/images/router/etc/ssl/certs/cert.pem new file mode 100644 index 0000000..34f35ba --- /dev/null +++ b/terraform/docker/images/router/etc/ssl/certs/cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFSjCCAzKgAwIBAgIULelntEyA7vrRApLWEBWcqBYBRmIwDQYJKoZIhvcNAQEL +BQAwEzERMA8GA1UEAwwIYXBwLnRlc3QwHhcNMTkwMjA0MTgxMjMyWhcNMjkwMjAx +MTgxMjMyWjATMREwDwYDVQQDDAhhcHAudGVzdDCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBANd9tqcNbcVKrLzdIX0RJ7+1mleOFyiaElOa1AkrBeOwIauk +yu4+4D0PukgN1HOvjgt1HOTDKN8eYCArYMDBB+rPNScXz6ZlYvvMLA/oYvC7zrbB +YvRoMEHVDC6FjcfNW9CvbB9WNwiiAghucUl1uIh/6Kk7GKnCXi3Akb5aG+CsEQ/T +tBJgeWDppQquXCvZOZFF5jpm95ffy6uo99c4vXRJQ45wwlsLIY7n/LdTViDDfI6U +7CHa4s+pDZj/ehRIWmp21hdnNhNOI4ew/2UBV18h0MsNz7QO7TXU/CP/EEoIQuoV +v300sYZd1TTAmSBHug2JhPhC5HMy5nXOSpiDKrM2VvBiZPn+INxJMig5TcOSwUhM +FCF+dPCGa6lDYkSK+QfIu1qZt9JEXOS0dG2oyOh2iBUyc8IRqwGneS5bvOscZcXp +7vUgu5DM5bptFZnpT2td7I9e81CJcOf2rz6NO9Hk74+MgxzEgEiJ3XXaeoEOnf99 +fkVnZ9KkBz54fAXkrGjbjO+7tLbWB8V8tW5oNdvZ6n4j3fjdJDX7gCsGqrdHvlRr +WZVjoWurN8O8f2zQ4hQWbXj+HBT31uzxedOXNuT5xfXqmDPOi2q1njSH/Bg/+u4X +AxCuZtWKirIp4NzEbSJAwDjc9AbbyhANemMk6qKXoZnBKTUKQRJLU6+UQrsxAgMB +AAGjgZUwgZIwHQYDVR0OBBYEFDgZ1HLO6R8Mf6ns5CpL3orek5D/ME4GA1UdIwRH +MEWAFDgZ1HLO6R8Mf6ns5CpL3orek5D/oRekFTATMREwDwYDVQQDDAhhcHAudGVz +dIIULelntEyA7vrRApLWEBWcqBYBRmIwDAYDVR0TBAUwAwEB/zATBgNVHREEDDAK +gghhcHAudGVzdDANBgkqhkiG9w0BAQsFAAOCAgEAxLK5d/HQII4sKRZoWeOeaTAD +bANUSEVTqgag7Vpvb9U+U9W2P64Z/uEbreRL36v4LLHLJIVkgyBS8TJTzYqSYzva +H/YZ5MgGh8hpLdsl7yVZ5/HHb6b2lNUBosdWMDDOyF+6BeAMdErhfvchicWkBI5Y +9slIsbV+WdICvbHuLuCVEEAOM0V5eiVoNRp9FnI66GrteveUc7SLn889PrBKI69c +RYmQ96USJoJ9lGKZy6ORbH3xj5GsdY+X30RRrKLvLOakhxMeEQciHqMl2NUzgOHS +SkXe7HBCnH42U2i2Kw6x5boq0tHMPy5FlOimMGOeCjNMOEdJ/2e8+y6jtwO3Wt92 +CxOdxTygBDMJOoaES8sW8n9wnc6Q78HKMFWteCfVVkgzASD0ro8oIdlsh69FSN96 +s78gU8ekdqElJmccbxbq7CnucxcdwvCfvoo181rS4E+jjWZIOk+8TAVtBp60wmgf +9zU0ixYEsX/8HZ9rfxLiDG7SaTF9QIkA6EtZPFptp0Sz1qTSOScTgCb+tBnE6ZDQ +JVmd2D/U6oOSHdKJ7xL4ZQQKcscOFZd3pEBI9/XsfilLMduK5Y6HptOlxsOel1v9 +k+DHpgmrQT9ONrba5EXk1ImphSb2v80ISOGeaWwArhFZWRWxlOovZ1zngsIBo981 +lTbr6CQzneoUwZqNz+M= +-----END CERTIFICATE----- diff --git a/terraform/docker/images/router/etc/ssl/certs/key.pem b/terraform/docker/images/router/etc/ssl/certs/key.pem new file mode 100644 index 0000000..1f6d904 --- /dev/null +++ b/terraform/docker/images/router/etc/ssl/certs/key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +pG/KIhHJ2sHTI8e0WH5kBUQEI5uw0/cF +-----END PRIVATE KEY----- diff --git a/terraform/docker/images/router/etc/traefik/dynamic_conf.yaml b/terraform/docker/images/router/etc/traefik/dynamic_conf.yaml new file mode 100644 index 0000000..5680885 --- /dev/null +++ b/terraform/docker/images/router/etc/traefik/dynamic_conf.yaml @@ -0,0 +1,12 @@ +tls: + stores: + default: + defaultCertificate: + certFile: /etc/ssl/certs/cert.pem + keyFile: /etc/ssl/certs/key.pem + +http: + middlewares: + redirect-to-https: + redirectScheme: + scheme: https diff --git a/terraform/docker/images/router/etc/traefik/traefik.yaml b/terraform/docker/images/router/etc/traefik/traefik.yaml new file mode 100644 index 0000000..a4c101a --- /dev/null +++ b/terraform/docker/images/router/etc/traefik/traefik.yaml @@ -0,0 +1,28 @@ +global: + checkNewVersion: false + sendAnonymousUsage: false + +providers: + docker: + exposedByDefault: false + file: + filename: /etc/traefik/dynamic_conf.yaml + +# # Uncomment get all DEBUG logs +#log: +# level: "DEBUG" + +# # Uncomment to view all access logs +#accessLog: {} + +api: + dashboard: true + insecure: true # No authentication are required + +entryPoints: + http: + address: ":80" + https: + address: ":443" + traefik: # this one exists by default + address: ":8080" diff --git a/terraform/docker/images/router/generate-ssl.sh b/terraform/docker/images/router/generate-ssl.sh new file mode 100644 index 0000000..ffd3bf9 --- /dev/null +++ b/terraform/docker/images/router/generate-ssl.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# Script used in dev to generate a basic SSL cert + +BASE=$(dirname $0) + +rm -rf mkdir $BASE/certs/ + +CERTS_DIR=$BASE/etc/ssl/certs + +mkdir -p $CERTS_DIR + +openssl req -x509 -sha256 -newkey rsa:4096 \ + -keyout $CERTS_DIR/key.pem \ + -out $CERTS_DIR/cert.pem \ + -days 3650 -nodes -config \ + $BASE/openssl.cnf diff --git a/terraform/docker/images/router/openssl.cnf b/terraform/docker/images/router/openssl.cnf new file mode 100644 index 0000000..ff68b84 --- /dev/null +++ b/terraform/docker/images/router/openssl.cnf @@ -0,0 +1,19 @@ +# Configuration used in dev to generate a basic SSL cert +[req] +default_bits = 2048 +prompt = no +default_md = sha256 +distinguished_name = dn +x509_extensions = v3_req + +[v3_req] +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always +basicConstraints=CA:true +subjectAltName = @alt_names + +[dn] +CN=app.test + +[alt_names] +DNS.1 = app.test diff --git a/terraform/docker/images/worker/Dockerfile b/terraform/docker/images/worker/Dockerfile new file mode 100644 index 0000000..fc7f59a --- /dev/null +++ b/terraform/docker/images/worker/Dockerfile @@ -0,0 +1,9 @@ +ARG PROJECT_NAME + +FROM ${PROJECT_NAME}_php-base + +WORKDIR /home/app/application + +COPY entrypoint.sh /var/lib + +ENTRYPOINT ["/var/lib/entrypoint.sh"] diff --git a/terraform/docker/images/worker/entrypoint.sh b/terraform/docker/images/worker/entrypoint.sh new file mode 100644 index 0000000..4665cae --- /dev/null +++ b/terraform/docker/images/worker/entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +if [ "$PROJECT_START_WORKERS" = "False" ]; then + echo "Worker not started" + exit 0 +fi + +exec "$@" diff --git a/terraform/docker/main.tf b/terraform/docker/main.tf new file mode 100644 index 0000000..412bd08 --- /dev/null +++ b/terraform/docker/main.tf @@ -0,0 +1,19 @@ + +terraform { + required_version = "> 1.0" + + required_providers { + docker = { + source = "kreuzwerker/docker" + } + } + + backend "local" { + path = "local.tfstate" + } +} + +provider "docker" { + host = "unix:///var/run/docker.sock" +} + diff --git a/terraform/docker/output.tf b/terraform/docker/output.tf new file mode 100644 index 0000000..986f165 --- /dev/null +++ b/terraform/docker/output.tf @@ -0,0 +1,10 @@ + +output "Frontend" { + description = "Frontend URL" + value = "https://www.${var.project_domain}" +} + +output "Postgres" { + description = "Database informations" + value = docker_container.postgres.env +} diff --git a/terraform/docker/resources.tf b/terraform/docker/resources.tf new file mode 100644 index 0000000..1219f17 --- /dev/null +++ b/terraform/docker/resources.tf @@ -0,0 +1,121 @@ + +resource "docker_network" "tf-starter_network" { + name = "${var.project_name}_network" +} + +// Router -------------------------------- +resource "docker_image" "router" { + name = "router" + build { + path = "images/router" + } +} + +resource "docker_container" "router" { + name = "${var.project_name}_router" + image = docker_image.router.latest + network_mode = "host" + mounts { + source = "/var/run/docker.sock" + target = "/var/run/docker.sock" + type = "bind" + } +} + + +// PHP base -------------------------------- +resource "docker_image" "php-base" { + name = "php-base" + build { + path = "images/php-base" + build_arg = { + PHP_VERSION : var.php_version + } + } +} + + +// Builder -------------------------------- +resource "docker_image" "builder" { + name = "builder" + depends_on = [docker_image.php-base] + build { + path = "images/builder" + build_arg = { + COMPOSER_MEMORY_LIMIT : "-1" + } + } +} + + +// Frontend -------------------------------- +resource "docker_image" "frontend" { + name = "frontend" + depends_on = [docker_image.php-base] + build { + path = "images/frontend" + build_arg = { + PROJECT_NAME : var.project_name + PHP_VERSION : var.php_version + } + } +} + +resource "docker_container" "frontend" { + name = "${var.project_name}_frontend" + image = docker_image.frontend.latest + network_mode = "${var.project_name}_network" + depends_on = [docker_container.postgres] + env = var.env + labels { + label = "traefik.enable" + value = "true" + } + labels { + label = "traefik.http.routers.${var.project_name}-frontend.rule" + value = "Host(`www.${var.project_domain}`)" + } + labels { + label = "traefik.http.routers.${var.project_name}-frontend.tls" + value = "true" + } + labels { + label = "traefik.http.routers.${var.project_name}-frontend-unsecure.rule" + value = "Host(`www.${var.project_domain}`)" + } + labels { + label = "traefik.http.routers.${var.project_name}-frontend-unsecure.middlewares" + value = "redirect-to-https@file" + } + + volumes { + host_path = "${path.cwd}/application" + container_path = "/home/app/application" + } +} + + +// Postgres -------------------------------- +resource "docker_image" "postgres" { + name = "postgres" + build { + path = "images/postgres" + } +} + +resource "docker_container" "postgres" { + name = "${var.project_name}_postgres" + image = docker_image.postgres.latest + network_mode = "${var.project_name}_network" + env = ["POSTGRES_USER=app", "POSTGRES_PASSWORD=app"] + volumes { + volume_name = "${var.project_name}-postgres-data" + container_path = "/var/lib/postgresql/data" + } +} + + + + + + diff --git a/terraform/docker/variables.tf b/terraform/docker/variables.tf new file mode 100644 index 0000000..0c04149 --- /dev/null +++ b/terraform/docker/variables.tf @@ -0,0 +1,28 @@ +variable "project_name" { + description = "Project name." + type = string + default = "tf-starter" +} + +variable "project_domain" { + description = "Project domain." + type = string + default = "tf-starter.test" +} + +variable "php_version" { + description = "PHP version." + type = string + default = "8.1" +} + +variable "env" { + description = "Environnement variables." + type = list(string) + default = [ + "APP_NAME=tf-starter", + "APP_DEBUG=true", + "APP_ENV=dev" + ] +} + diff --git a/terraform/docker/variables.tfvars b/terraform/docker/variables.tfvars new file mode 100644 index 0000000..4e35f0a --- /dev/null +++ b/terraform/docker/variables.tfvars @@ -0,0 +1,2 @@ +# Add here your custom variables. All variables must be defined in ./variables.tf. +