DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Building a Flask Web Application With Docker: A Step-by-Step Guide
  • Introduction to Data Replication With MariaDB Using Docker Containers
  • Identifying, Exploiting, and Preventing Host Header Attacks on Web Servers
  • KubeMQ: A Modern Alternative to Kafka

Trending

  • Scalable System Design: Core Concepts for Building Reliable Software
  • Google Cloud Document AI Basics
  • Emerging Data Architectures: The Future of Data Management
  • GDPR Compliance With .NET: Securing Data the Right Way
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. Deploy a Golang Web Application and Couchbase as Docker Containers

Deploy a Golang Web Application and Couchbase as Docker Containers

Learn how to deploy a Golang web application as a Docker container alongside Couchbase using microservices and Docker images.

By 
Nic Raboy user avatar
Nic Raboy
·
May. 17, 17 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
4.8K Views

Join the DZone community and get the full member experience.

Join For Free

In my development series regarding Docker containers for the web application developer, I went over deploying Java and Node.js applications as containers alongside Couchbase Server Containers. This time around I thought it would be cool to deploy a Golang web application as a Docker container alongside Couchbase.

The process is very similar to what I have already demonstrated in previous tutorials, but it is worth exploring. We’re going to explore containerizing an application that I had explained in a previous tutorial on the topic of URL shortening services.

If you’re interested, you can check out the articles Use Docker to Deploy a Containerized Java With Couchbase Web Application and Deploy a Node.js With Couchbase Web Application as Docker Containers, depending on your language preferences.

The Requirements

There is only one dependency that must be met to be successful with this guide. You need Docker installed on a host machine. You don’t need Golang installed or Couchbase Server — that is the beauty of the Docker Engine.

While you don’t have to, I would recommend becoming familiar with the application in question. To learn about the code behind the application, check out the tutorial I wrote called Create a URL Shortener With Golang and Couchbase NoSQL.

Establishing a Docker Project for the Golang Application

The source code to the application, and what we’ll be bundling, can be seen below. You should save it as a Go source code file such as main.go.

package main
 
import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"time"
 
	"github.com/couchbase/gocb"
	"github.com/gorilla/mux"
	"github.com/speps/go-hashids"
)
 
type MyUrl struct {
	ID       string `json:"id,omitempty"`
	LongUrl  string `json:"longUrl,omitempty"`
	ShortUrl string `json:"shortUrl,omitempty"`
}
 
var bucket *gocb.Bucket
var bucketName string
 
func ExpandEndpoint(w http.ResponseWriter, req *http.Request) {
	var n1qlParams []interface{}
	query := gocb.NewN1qlQuery("SELECT `" + bucketName + "`.* FROM `" + bucketName + "` WHERE shortUrl = $1")
	params := req.URL.Query()
	n1qlParams = append(n1qlParams, params.Get("shortUrl"))
	rows, _ := bucket.ExecuteN1qlQuery(query, n1qlParams)
	var row MyUrl
	rows.One(&row)
	json.NewEncoder(w).Encode(row)
}
 
func CreateEndpoint(w http.ResponseWriter, req *http.Request) {
	var url MyUrl
	_ = json.NewDecoder(req.Body).Decode(&url)
	var n1qlParams []interface{}
	n1qlParams = append(n1qlParams, url.LongUrl)
	query := gocb.NewN1qlQuery("SELECT `" + bucketName + "`.* FROM `" + bucketName + "` WHERE longUrl = $1")
	rows, err := bucket.ExecuteN1qlQuery(query, n1qlParams)
	if err != nil {
		w.WriteHeader(401)
		w.Write([]byte(err.Error()))
		return
	}
	var row MyUrl
	rows.One(&row)
	if row == (MyUrl{}) {
		hd := hashids.NewData()
		h := hashids.NewWithData(hd)
		now := time.Now()
		url.ID, _ = h.Encode([]int{int(now.Unix())})
		url.ShortUrl = "http://localhost:12345/" + url.ID
		bucket.Insert(url.ID, url, 0)
	} else {
		url = row
	}
	json.NewEncoder(w).Encode(url)
}
 
func RootEndpoint(w http.ResponseWriter, req *http.Request) {
	params := mux.Vars(req)
	var url MyUrl
	bucket.Get(params["id"], &url)
	http.Redirect(w, req, url.LongUrl, 301)
}
 
func main() {
	router := mux.NewRouter()
	cluster, _ := gocb.Connect("couchbase://" + os.Getenv("COUCHBASE_HOST"))
	bucketName = os.Getenv("COUCHBASE_BUCKET")
	bucket, _ = cluster.OpenBucket(bucketName, "")
	router.HandleFunc("/{id}", RootEndpoint).Methods("GET")
	router.HandleFunc("/expand/", ExpandEndpoint).Methods("GET")
	router.HandleFunc("/create", CreateEndpoint).Methods("PUT")
	log.Fatal(http.ListenAndServe(":12345", router))
}

The only difference between the code above and the previous tutorial on the subject is the use of the os.Getenv("COUCHBASE_HOST") and os.Getenv("COUCHBASE_BUCKET")commands. This will allow us to define the Couchbase connection information at container runtime via environment variables rather than hardcoding it into the application.

If you had Couchbase Server running, you could launch the web application by doing:

env COUCHBASE_HOST=localhost COUCHBASE_BUCKET=default go run *.go

Of course, the project would need to be in your $GOPATH, but it would be accessible from http://localhost:12345 as defined in the code.

The goal here is not to run this project locally but via a Docker container. Create a Dockerfile file next to the main.go file or whatever you called it. The Dockerfile file should contain the following:

FROM golang:alpine

RUN apk update && apk add git

COPY . /go/src/app/

WORKDIR /go/src/app

RUN go get -d -v
RUN go install -v

CMD ["app"]

As a base, we’ll be using the official Golang Alpine Linux image for Docker, but we’ll be customizing it. During build time, we are installing Git, copying the main.go file to the image, installing the project dependencies found in the import section, and installing the application. At runtime, we are executing the installed application.

To build an image from our custom Docker blueprint, we would execute the following:

docker build -t golang-project .

After all the compile-time steps complete, we’ll be left with a golang-project Docker image. Before we try to run this image, we need to worry about Couchbase. While we could run Couchbase outside a container, where is the fun in that?

Creating a Custom Couchbase Server Docker Image

Just like with Golang, an official Docker image exists for Couchbase Server. While it is a perfectly acceptable solution, it is not an automated solution. This means that you’ll have to manually configure the database after the container starts. We probably want to avoid that.

Instead, create a directory somewhere on your computer with a Dockerfile file and configure.sh file in it. The plan is to create a Docker blueprint that will execute the configuration script for us.

Open the Dockerfile file and include the following:

FROM couchbase

COPY configure.sh /opt/couchbase

CMD ["/opt/couchbase/configure.sh"]

We’re basically just copying the script into the base image and running it. The real magic happens inside of the script.

Open the configure.sh file and include the following:

set -m

/entrypoint.sh couchbase-server &

sleep 15

curl -v -X POST http://127.0.0.1:8091/pools/default -d memoryQuota=512 -d indexMemoryQuota=512

curl -v http://127.0.0.1:8091/node/controller/setupServices -d services=kv%2cn1ql%2Cindex

curl -v http://127.0.0.1:8091/settings/web -d port=8091 -d username=$COUCHBASE_ADMINISTRATOR_USERNAME -d password=$COUCHBASE_ADMINISTRATOR_PASSWORD

curl -i -u $COUCHBASE_ADMINISTRATOR_USERNAME:$COUCHBASE_ADMINISTRATOR_PASSWORD -X POST http://127.0.0.1:8091/settings/indexes -d 'storageMode=memory_optimized'

curl -v -u $COUCHBASE_ADMINISTRATOR_USERNAME:$COUCHBASE_ADMINISTRATOR_PASSWORD -X POST http://127.0.0.1:8091/pools/default/buckets -d name=$COUCHBASE_BUCKET -d bucketType=couchbase -d ramQuotaMB=128 -d authType=sasl -d saslPassword=$COUCHBASE_BUCKET_PASSWORD

sleep 15

curl -v http://127.0.0.1:8093/query/service -d "statement=CREATE PRIMARY INDEX ON `$COUCHBASE_BUCKET`"

fg 1

Couchbase Server has a RESTful interface that will allow us to complete the configuration wizard through a script. The above commands will define instance specs and services, administrative credentials, and a Bucket.

You’ll notice things like $COUCHBASE_ADMINISTRATOR_USERNAME within the script. Just like in the Golang application we are leveraging environment variables to prevent having to hardcode values into our image. These values can be defined during the container deployment.

More information on provisioning a Couchbase Server container can be found in a previous article that I wrote on the subject.

Finally, we can build this custom Couchbase Server image. From the Docker Shell, execute the following:

docker build -t couchbase-custom .

The above command will leave us with a couchbase-custom image.

Deploying the Containerized Microservice

There are a few ways to deploy the images that we built. We’ll explore two of them here.

Given what we know about our images, we can deploy our containers with the following commands:

docker run -d \
    -p 8091-8093:8091-8093 \
    -e COUCHBASE_ADMINISTRATOR_USERNAME=Administrator \
    -e COUCHBASE_ADMINISTRATOR_PASSWORD=password \
    -e COUCHBASE_BUCKET=default \
    -e COUCHBASE_BUCKET_PASSWORD= \
    --network="docker_default" \
    --name couchbase \
    couchbase-custom

The above command will deploy Couchbase Server while mapping the necessary ports to the host operating system. We’re passing each environment variable in with the command and defining an operating network. The network is important because you want both your database and application to be on the same container network.

docker run -d \
    -p 12345:12345 \
    -e COUCHBASE_HOST=couchbase \
    -e COUCHBASE_BUCKET=default \
    --network="docker_default" \
    --name golang 
    golang-project

The above command will deploy our Golang image while mapping the correct ports again. For the host, you’ll notice that we’re using couchbase , which is actually the name of our other container. The container names also act as host names.

The commands you just saw are a very manual way to do things in my opinion. Instead, you can create a Docker Compose file to handle this for you.

Create a docker-compose.yml file somewhere on your computer with the following:

version: '2'

services:
    couchbase:
        image: couchbase-custom
        ports:
            - 8091:8091
            - 8092:8092
            - 8093:8093
        environment:
            - COUCHBASE_ADMINISTRATOR_USERNAME=Administrator
            - COUCHBASE_ADMINISTRATOR_PASSWORD=password
            - COUCHBASE_BUCKET=default
            - COUCHBASE_BUCKET_PASSWORD=

    golang:
        image: golang-project
        ports:
            - 12345:12345
        environment:
            - COUCHBASE_HOST=couchbase
            - COUCHBASE_BUCKET=default
        restart: always

Everything in a Compose file will be on the same network. To deploy each service, execute the following:

docker-compose run -d --service-ports couchbase
docker-compose run -d --service-ports golang

If you’re familiar with Docker Compose, you’ll be familiar with docker-compose up, but we can’t use that here. Couchbase Server doesn’t have a mechanism to tell us it is ready, so we don’t want the Golang application to try to connect before it is configured. Definitely not a big deal when it comes to container deployment.

Conclusion

You just saw how to create a Golang microservice as a Docker container that communicates to the Couchbase Server, also running within a Docker container. By turning your application into a Docker image it becomes very easy to distribute because you won’t have to worry about the environment you’re trying to deploy to. As long as the Docker Engine is available you can deploy your application. A useful example of this would be in the continuous deployment of containers using Jenkins.

Want to see how to containerize your Java application? Check out this tutorial I wrote. I also have a tutorial for containerizing a Node.js application here.

Docker (software) application Web application Golang Web Service Couchbase Server

Published at DZone with permission of Nic Raboy, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Building a Flask Web Application With Docker: A Step-by-Step Guide
  • Introduction to Data Replication With MariaDB Using Docker Containers
  • Identifying, Exploiting, and Preventing Host Header Attacks on Web Servers
  • KubeMQ: A Modern Alternative to Kafka

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: