Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions auth-api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

# Phase 1: Defining build phase to compile code.
FROM golang:1.18-alpine AS builder

WORKDIR /app

COPY . .

# Env variable useful to define newer module system tha was implemented on Go 1.11.

ENV GO111MODULE=on

# Download dependencies and compile application process.

RUN go mod init github.com/bortizf/microservice-app-example/tree/master/auth-api && \
go mod tidy &&\
go build -o auth-api .

# Phase 2: Image for runtime

FROM alpine:latest

# DevSecOps practice: Avoid the use of root user on container by adding other user with limited permissions.

RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app

# From phase 1 we copy the compiled file and then execute it (Remenber the alias "builder" assign in phase 1).

COPY --from=builder /app/auth-api .

RUN chown appuser:appgroup /app/auth-api

# Must specify appuser to avoid the use of root user.

USER appuser

CMD ["./auth-api"]



124 changes: 124 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
services:

#-------------------------User-auth context-------------------------

#Useful to visualize and analize microservices request tracking.
zipkin:
image: openzipkin/zipkin
ports:
- "${ZIPKIN_PORT}:${ZIPKIN_PORT}"
environment:
- CORS_ALLOWED_ORIGINS=*
networks:
- logger
- users-auth

auth-api:
build:
context: ./auth-api/
dockerfile: Dockerfile

#TODO: must implement arg to pass env variables from github secrets.
environment:
JWT_SECRET: ${JWT_SECRET}
USERS_API_ADDRESS: ${USERS_API_ADDRESS}
AUTH_API_PORT: ${AUTH_API_PORT}

ports:
- "${AUTH_API_PORT}:${AUTH_API_PORT}"
networks:
- users-auth
depends_on:
- users-api

users-api:
build:
context: ./users-api/
dockerfile: Dockerfile
environment:
#TODO: must implement arg to pass env variables from github secrets.
JWT_SECRET: ${JWT_SECRET}
SERVER_PORT: ${USERS_API_PORT}
ports:
- "${USERS_API_PORT}:${USERS_API_PORT}"
networks:
- users-auth



#-------------------------Logs and Messaging-------------------------

redis:
image: redis:7.0
ports:
- "${REDIS_PORT}:${REDIS_PORT}"
networks:
- logger


logg-processor:
build:
context: ./log-message-processor/
dockerfile: Dockerfile
environment:
#TODO: must implement arg to pass env variables from github secrets.
REDIS_HOST: "${REDIS_HOST}"
REDIS_PORT: "${REDIS_PORT}"
REDIS_CHANNEL: "${REDIS_CHANNEL}"
networks:
- logger
depends_on:
- redis

todos-api:
build:
context: ./todos-api/
dockerfile: Dockerfile
environment:
#TODO: must implement arg to pass env variables from github secrets.
JWT_SECRET: ${JWT_SECRET}
TODO_API_PORT: ${TODO_API_PORT}
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT}
REDIS_CHANNEL: ${REDIS_CHANNEL}
ports:
- "${TODO_API_PORT}:${TODO_API_PORT}"
networks:
- logger
depends_on:
- auth-api

#-------------------------Frontend-------------------------


frontend:
build:
context: ./frontend
dockerfile: Dockerfile
args:
- VUE_APP_ZIPKIN_URL="${ZIPKIN_URL}"

environment:
AUTH_API_ADDRESS: "http://auth-api:${AUTH_API_PORT}"
TODOS_API_ADDRESS: "http://todos-api:${TODO_API_PORT}"
VUE_APP_ZIPKIN_URL: "${ZIPKIN_URL}"
ports:
- "80:80"
networks:
- users-auth
- logger
depends_on:
- auth-api
- todos-api


#-------------------------Networks-------------------------

networks:
users-auth:
driver: bridge
logger:
driver: bridge



1 change: 1 addition & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ yarn-error.log*
*.ntvs*
*.njsproj
*.sln
.env
42 changes: 42 additions & 0 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Phase 1: Defining build phase to compile code.

FROM node:8.17.0-slim as builder

# Ensuring the env variables can be use on building phase
ARG VUE_APP_ZIPKIN_URL
ENV VUE_APP_ZIPKIN_URL=$VUE_APP_ZIPKIN_URL

WORKDIR /app

# Copy all dependecies to be install
COPY package*.json ./
RUN npm install npm@6.13.4 -g && \
npm install

COPY . .
RUN npm run build

# Phase 2: Web server to expose frontend, must redirect request trought nginx proxy.
FROM nginx:alpine

# We must install gettex to insert env varibales on default.conf.template to be used as
# nginx configuration.
RUN apk add --no-cache gettext

# We remove nginx previous files.
RUN rm -rf /etc/nginx/conf.d/*

#Copy nginx template or blueprint where env variables will be insert.
COPY default.conf.template /etc/nginx/conf.d/default.conf.template

#Must execute .sh to apply gettext process and execute nginx web server
COPY entrypoint.sh /entrypoint.sh

# From phase 1 we copy the compiled file and then execute it (Remenber the alias "builder" assign in phase 1).

COPY --from=builder /app/dist /usr/share/nginx/html

#Convert entrypoint executable
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
76 changes: 76 additions & 0 deletions frontend/default.conf.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
server {
listen 80;
server_name localhost;

root /usr/share/nginx/html;
index index.html;

location / {
try_files $uri $uri/ /index.html;
}

location /auth-api/ {

#We must add "/" at the end to avoid the use of "/auth-api" prefix

proxy_pass ${AUTH_API_ADDRESS}/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


# CORS configuration
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';

# Preflight requests manager
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}

location /todos-api/ {

#Define URL based on env varibles.

#We must add "/" at the end to avoid the use of "/auth-api" prefix

proxy_pass ${TODOS_API_ADDRESS}/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


# CORS configuration
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';

# Management of preflight requests, and define allowed headers
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}

location ~* \.(?:css|js|json|woff2?|ttf|eot|svg|png|jpg|jpeg|gif|ico)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000";
}

add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
}
7 changes: 7 additions & 0 deletions frontend/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

# Currently we are using gettext to insert this env variables on the specified file.
envsubst '${AUTH_API_ADDRESS} ${TODOS_API_ADDRESS}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf

# Run Nginx web server.
exec nginx -g 'daemon off;'
7 changes: 4 additions & 3 deletions frontend/src/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import decode from 'jwt-decode'

/**
* @var{string} LOGIN_URL The endpoint for logging in. This endpoint should be proxied by Webpack dev server
* and maybe nginx in production (cleaner calls and avoids CORS issues).
* and maybe nginx in production (cleaner calls and avoids CORS issues). Notice we add "/auth-api/" prefix
* to redirect request with best practices.
*/
const LOGIN_URL = window.location.protocol + '//' + window.location.host + '/login'
const LOGIN_URL = window.location.protocol + '//' + window.location.host + '/auth-api/login'
const ROLE_ADMIN = 'ADMIN'

/**
* Auth Plugin
*
*
* (see https://vuejs.org/v2/guide/plugins.html for more info on Vue.js plugins)
*
* Handles login and token authentication using OAuth2.
Expand Down
12 changes: 8 additions & 4 deletions frontend/src/components/Todos.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ import AppNav from '@/components/AppNav'
import TodoItem from '@/components/TodoItem'
import Spinner from '@/components/common/Spinner'

const BASE_URL = "/todos-api"

export default {

name: 'todos',
components: {AppNav, TodoItem, Spinner},
props: {
Expand All @@ -71,7 +74,8 @@ export default {
return {
isProcessing: false,
errorMessage: '',
newTask: ''
newTask: '',
url: BASE_URL
}
},
created () {
Expand All @@ -86,7 +90,7 @@ export default {
loadTasks () {
this.isProcessing = true
this.errorMessage = ''
this.$http.get('/todos').then(response => {
this.$http.get( `${BASE_URL}/todos`).then(response => {
for (var i in response.body) {
this.tasks.push(response.body[i])
}
Expand All @@ -106,7 +110,7 @@ export default {
content: this.newTask
}

this.$http.post('/todos', task).then(response => {
this.$http.post(`${BASE_URL}/todos`, task).then(response => {
this.newTask = ''
this.isProcessing = false
this.tasks.push(task)
Expand All @@ -123,7 +127,7 @@ export default {
this.isProcessing = true
this.errorMessage = ''

this.$http.delete('/todos/' + item.id).then(response => {
this.$http.delete(`${BASE_URL}/todos/` + item.id).then(response => {
this.isProcessing = false
this.tasks.splice(index, 1)
}, error => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/zipkin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from 'zipkin'
import {HttpLogger} from 'zipkin-transport-http'
import {zipkinInterceptor} from 'zipkin-instrumentation-vue-resource'
const ZIPKIN_URL = window.location.protocol + '//' + window.location.host + '/zipkin'
const ZIPKIN_URL = process.env.VUE_APP_ZIPKIN_URL || 'http://localhost:9411/api/v2/spans';
/**
* Tracing plugin that uses Zipkin. Initiates new traces with outgoing requests
* and injects appropriate headers.
Expand Down
Loading