Skip to content

04‐ Containerizing the User Service with Docker

Rabieh Fashwall edited this page Jan 22, 2025 · 4 revisions

We'll containerize our User service using Docker and introduce Viper for environment-based configuration. We'll create a Dockerfile to build a Docker image of our service and use Docker Compose to define and run our User service along with a MySQL database.

diagram

Goals

By the end of this branch, you'll be able to:

  • Use Viper to manage environment variables for your User service.
  • Build a Docker image for your User service.
  • Define and run the User service and MySQL database using Docker Compose.

Steps

  1. Create Branch:

    git checkout 03-add-env-variables-and-dockerise
  2. Install Viper:

    go get github.com/spf13/viper
  3. Update user-service/cmd/main.go to use Viper for Configuration:

    • Import the Viper package.
    • Configure Viper to read from environment variables.
    • Access database configuration from environment variables using Viper.
    func main() {
        // Configure Viper to read from environment variables.
        viper.SetEnvPrefix("USER_SERVICE") // Set environment variable prefix 
        viper.AutomaticEnv()               // Enable Viper to read from environment variables.
    
        // Database Configuration from Environment Variables
        dbHost := viper.GetString("DB_HOST")
        dbPort := viper.GetString("DB_PORT") 
        dbUser := viper.GetString("DB_USER")
        dbPass := viper.GetString("DB_PASS")
        dbName := viper.GetString("DB_NAME") 
    
        // ... (Rest of the main function)
    }
  4. Create a Dockerfile (user-service/Dockerfile):

    FROM golang:1.23.4-alpine
    
    WORKDIR /app
    
    COPY . .
    
    RUN go mod tidy
    RUN go build -o user-service ./cmd
    
    CMD ["./user-service"]
    
  5. Create a Docker Compose File (docker-compose.yaml):

version: '3.8' 

services:
  user-service:
    build: 
      context: ./user-service
      dockerfile: Dockerfile 
    container_name: user-service
    ports: 
      - "3000:3000"
    environment:
      - USER_SERVICE_DB_HOST=mysql-server 
      - USER_SERVICE_DB_PORT=3306
      - USER_SERVICE_DB_USER=root
      - USER_SERVICE_DB_PASS=root
      - USER_SERVICE_DB_NAME=user_tracker
    depends_on: 
      - mysql-server 

  mysql-server:
    image: mysql:latest
    container_name: mysql-server
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: user_tracker
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./init.sh:/docker-entrypoint-initdb.d/init.sh
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h localhost"]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 10s

volumes:
  mysql_data:
  1. Create init.sh to setup the DB
#!/bin/bash
set -e

mysql -u root -proot <<-EOSQL

CREATE DATABASE IF NOT EXISTS user_tracker;
USE user_tracker;

CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL
);

CREATE DATABASE IF NOT EXISTS task_tracker;
USE task_tracker;

CREATE TABLE IF NOT EXISTS tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    assignee_id INT NULL,
    title VARCHAR(255) NOT NULL,
    description TEXT,
    status VARCHAR(50)
);

EOSQL
  1. Run the Application using Docker Compose:

    docker-compose up -d --build
    • -d: Runs the containers in detached mode (in the background).
    • --build: Forces Docker Compose to rebuild the images even if they already exist.

Testing

  • Once the containers are running, you can use the same curl commands as before to test the API endpoints. The only difference is that you should now send the requests to http://localhost:3000 since the User service's port is mapped to port 3000 on your host machine.

Clone this wiki locally