Docker a beginners guide
Tags: docker, webdev, tutorial, node
Published: 2024-06-16 15:15:36

Docker is a platform for developing, shipping, and running applications in containers. Containers are lightweight and contain everything needed to run an application, making them portable and consistent across environments.

Here’s a brief tutorial on Docker, including creating containers, networking between containers, and setting up a simple multi-container application involving a database, cache, and services written in Node.js and Go.

## **1. Install Docker**

Install Docker from Docker’s official [website](https://www.docker.com/)

## **2. Basic Docker Commands**

**Pull an image:**

`docker pull <image-name>`

Example:

`docker pull node:14`

**Run a container:**

`docker run -d – name <container-name> <image-name>`

Example:

`docker run -d – name my-node-container node:14`

**List running containers:**

`docker ps`

**Stop a container:**

`docker stop <container-name>`

**Remove a container:**

`docker rm <container-name>`

## **3. Creating a Node.js Application Container**

**Create a simple Node.js application:**

```
mkdir node-app
cd node-app
npm init -y
npm install express
```

**2. Create `app.js`:**

```
const express = require(‘express’);
const app = express();
const PORT = 3000;

app.get('/', (req, res) => {
  res.send('Hello from Node.js!');
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
```

## **3. Create `Dockerfile:**

Dockerfile

```
FROM node:14

WORKDIR /usr/src/app

COPY package.json ./

RUN npm install

COPY . .

EXPOSE 3000

CMD ["node", "app.js"]
```


## **4. Build the Docker image:**

`docker build -t node-app .`

## **5. Run the container:**

`docker run -d – name node-app-container -p 3000:3000 node-app`

**Creating a Go Application Container**

**Create a simple Go application:**


```
mkdir go-app
cd go-app
```

**2. Create `main.go`:**


```
package main

import (
  "fmt"
  "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello from Go!")
}

func main() {
  http.HandleFunc("/", handler)
  http.ListenAndServe(":8080", nil)
}
```


**3. Create `Dockerfile`:**

Dockerfile


```
FROM golang:1.16

WORKDIR /app

COPY . .

RUN go build -o main .

EXPOSE 8080

CMD ["./main"]
```

**4. Build the Docker image:**

`docker build -t go-app .`

**5. Run the container:**

`docker run -d – name go-app-container -p 8080:8080 go-app`

**5. Setting Up a Database Container**

Run a PostgreSQL container:

```
docker run -d – name postgres-container -e POSTGRES_PASSWORD=mysecretpassword -e POSTGRES_DB=mydatabase -p 5432:5432 postgres
```

**6. Setting Up a Redis Cache Container**

**Run a Redis container:**
`docker run -d – name redis-container -p 6379:6379 redis`

**7. Networking Between Containers**

Docker provides several ways to network containers. The simplest way is to use Docker’s default bridge network.

**Create a custom network:**

`docker network create my-network`

**2. Run containers in the same network:**

```
docker run -d – name postgres-container – network my-network -e POSTGRES_PASSWORD=mysecretpassword -e POSTGRES_DB=mydatabase postgres
docker run -d – name redis-container – network my-network redis
docker run -d – name node-app-container – network my-network -p 3000:3000 node-app
docker run -d – name go-app-container – network my-network -p 8080:8080 go-app
```

**8. Connecting Services to Database and Cache**

Example Node.js (app.js) connecting to PostgreSQL and Redis:

**Install dependencies:**

`npm install pg redis`

Modify `app.js`:

```
const express = require('express');
const { Pool } = require('pg');
const redis = require('redis');
const app = express();
const PORT = 3000;
const pool = new Pool({
  user: 'postgres',
  host: 'postgres-container',
  database: 'mydatabase',
  password: 'mysecretpassword',
  port: 5432,
});

const client = redis.createClient({
  host: 'redis-container',
  port: 6379,
});

app.get('/', async (req, res) => {
  const result = await pool.query('SELECT NOW()');
  
  client.set('key', 'value');

  client.get('key', (err, value) => {
     res.send(`PostgreSQL time: ${result.rows[0].now}, Redis value: ${value}`);
  });

});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
```

Example Go (`main.go`) connecting to PostgreSQL and Redis:

**Install dependencies:**

`go get github.com/lib/pq
go get github.com/go-redis/redis/v8`

**2. Modify `main.go`:**

```
package main

import (
  "context"
  "database/sql"
  "fmt"
  "net/http"
  "github.com/go-redis/redis/v8"
  _ "github.com/lib/pq"
)

var ctx = context.Background()

func handler(w http.ResponseWriter, r *http.Request) {
  connStr := "user=postgres password=mysecretpassword dbname=mydatabase host=postgres-container sslmode=disable"
  db, err := sql.Open("postgres", connStr)
  
  if err != nil {
    panic(err)
  }
 
  defer db.Close()
  
  var now string
  err = db.QueryRow("SELECT NOW()").Scan(&now)

  if err != nil {
    panic(err)
  }
  
  rdb := redis.NewClient(&redis.Options{
    Addr: "redis-container:6379",
  })
  
  err = rdb.Set(ctx, "key", "value", 0).Err()
  
  if err != nil {
  panic(err)
  }

  val, err := rdb.Get(ctx, "key").Result()
  
  if err != nil {
    panic(err)
  }
  
  fmt.Fprintf(w, "PostgreSQL time: %s, Redis value: %s", now, val)
}

func main() {
  http.HandleFunc("/", handler)
  http.ListenAndServe(":8080", nil)
}
```

## **9. Docker Compose**

To simplify the process, you can use Docker Compose to define and run multi-container Docker applications.

Create `docker-compose.yml`:

```
version: '3'

services:
  postgres:
    image: postgres
    environment:
      POSTGRES_PASSWORD: mysecretpassword
      POSTGRES_DB: mydatabase
    networks:
      - my-network

  redis:
    image: redis
    networks:
      - my-network

  node-app:
    build: ./node-app
    ports:
      - "3000:3000"
    networks:
      - my-network

  go-app:
    build: ./go-app
    ports:
      - "8080:8080"
    networks:
      - my-network

networks:
  my-network:
    driver: bridge
```

**Run the application:**

`docker-compose up – build`

By following this tutorial, you can set up a multi-container application with Docker, including networking between containers and connecting services to a database and cache.