Welcome to Section 17! This section focuses on creating professional build systems and deployment pipelines for your blockchain application. You'll learn how to automate builds, manage releases, and deploy your application to production environments.
By the end of this section, you will be able to:
✅ Create Professional Makefiles: Build robust and maintainable build scripts
✅ Implement Cross-Compilation: Build for multiple platforms and architectures
✅ Set Up Docker Containerization: Create production-ready containers
✅ Design CI/CD Pipelines: Automate build, test, and deployment processes
✅ Manage Release Versions: Implement semantic versioning and release management
✅ Deploy to Production: Safely deploy applications to production environments
✅ Automate Deployment: Create reliable deployment automation strategies
Before starting this section, ensure you have:
- Phase 1: Basic blockchain implementation (all sections)
- Phase 2: Advanced features and APIs (all sections)
- Phase 3: User experience and interface development (all sections)
- Section 16: Testing and quality assurance
- Build Tools: Familiarity with Make, Docker, and CI/CD concepts
- Go Experience: Understanding of Go build system and modules
In this section, you'll create a comprehensive build and deployment system that includes:
- Professional Makefile: Automated build, test, and deployment tasks
- Cross-Platform Builds: Support for multiple operating systems and architectures
- Docker Containerization: Production-ready container images
- CI/CD Pipeline: Automated build, test, and deployment workflows
- Release Management: Semantic versioning and release automation
- Deployment Scripts: Automated deployment to various environments
- Monitoring Integration: Build and deployment monitoring
- Make: Build automation and task management
- Docker: Containerization and deployment
- GitHub Actions: CI/CD pipeline automation
- Go Build: Cross-compilation and binary management
- Semantic Versioning: Release version management
- Environment Management: Configuration and secrets management
- Monitoring Tools: Build and deployment tracking
# Makefile for Blockchain Application
.PHONY: help build test clean docker-build docker-run deploy
# Variables
APP_NAME := blockchain
VERSION := $(shell git describe --tags --always --dirty)
BUILD_TIME := $(shell date -u '+%Y-%m-%d_%H:%M:%S')
GIT_COMMIT := $(shell git rev-parse --short HEAD)
LDFLAGS := -ldflags "-X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME) -X main.GitCommit=$(GIT_COMMIT)"
# Go build settings
GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)
CGO_ENABLED ?= 0
# Docker settings
DOCKER_IMAGE := $(APP_NAME):$(VERSION)
DOCKER_LATEST := $(APP_NAME):latest
DOCKER_REGISTRY ?= localhost:5000
# Build directories
BUILD_DIR := build
BIN_DIR := $(BUILD_DIR)/bin
DIST_DIR := $(BUILD_DIR)/dist
# Default target
help: ## Show this help message
@echo 'Usage: make [target]'
@echo ''
@echo 'Targets:'
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
# Development targets
build: ## Build the application for current platform
@echo "Building $(APP_NAME) for $(GOOS)/$(GOARCH)..."
@mkdir -p $(BIN_DIR)
go build $(LDFLAGS) -o $(BIN_DIR)/$(APP_NAME) ./cmd/main.go
@echo "Build complete: $(BIN_DIR)/$(APP_NAME)"
build-all: ## Build for all supported platforms
@echo "Building for all platforms..."
@mkdir -p $(BIN_DIR)
$(MAKE) build GOOS=linux GOARCH=amd64
$(MAKE) build GOOS=linux GOARCH=arm64
$(MAKE) build GOOS=darwin GOARCH=amd64
$(MAKE) build GOOS=darwin GOARCH=arm64
$(MAKE) build GOOS=windows GOARCH=amd64
@echo "All builds complete"
test: ## Run tests
@echo "Running tests..."
go test -v -race -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
@echo "Test coverage report: coverage.html"
test-short: ## Run tests without race detection
@echo "Running tests (short)..."
go test -v ./...
lint: ## Run linter
@echo "Running linter..."
golangci-lint run
fmt: ## Format code
@echo "Formatting code..."
go fmt ./...
goimports -w .
vet: ## Run go vet
@echo "Running go vet..."
go vet ./...
# Cleanup targets
clean: ## Clean build artifacts
@echo "Cleaning build artifacts..."
rm -rf $(BUILD_DIR)
rm -f coverage.out coverage.html
@echo "Clean complete"
# Docker targets
docker-build: ## Build Docker image
@echo "Building Docker image: $(DOCKER_IMAGE)"
docker build -t $(DOCKER_IMAGE) -t $(DOCKER_LATEST) .
@echo "Docker build complete"
docker-push: ## Push Docker image to registry
@echo "Pushing Docker image to registry..."
docker tag $(DOCKER_IMAGE) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE)
docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE)
@echo "Docker push complete"
docker-run: ## Run Docker container
@echo "Running Docker container..."
docker run -p 8080:8080 --name $(APP_NAME) $(DOCKER_IMAGE)
docker-stop: ## Stop Docker container
@echo "Stopping Docker container..."
docker stop $(APP_NAME) || true
docker rm $(APP_NAME) || true
# Release targets
release: ## Create a new release
@echo "Creating release $(VERSION)..."
$(MAKE) clean
$(MAKE) build-all
$(MAKE) docker-build
$(MAKE) create-release-package
@echo "Release $(VERSION) created"
create-release-package: ## Create release package
@echo "Creating release package..."
@mkdir -p $(DIST_DIR)
@cd $(BIN_DIR) && tar -czf ../dist/$(APP_NAME)-$(VERSION)-$(GOOS)-$(GOARCH).tar.gz *
@echo "Release package: $(DIST_DIR)/$(APP_NAME)-$(VERSION)-$(GOOS)-$(GOARCH).tar.gz"
# Development workflow
dev: fmt lint test build ## Development workflow: format, lint, test, build
ci: test lint build docker-build ## CI workflow: test, lint, build, docker
# Deployment targets
deploy-dev: ## Deploy to development environment
@echo "Deploying to development environment..."
kubectl apply -f k8s/dev/
@echo "Development deployment complete"
deploy-staging: ## Deploy to staging environment
@echo "Deploying to staging environment..."
kubectl apply -f k8s/staging/
@echo "Staging deployment complete"
deploy-prod: ## Deploy to production environment
@echo "Deploying to production environment..."
kubectl apply -f k8s/prod/
@echo "Production deployment complete"
# Monitoring targets
logs: ## View application logs
@echo "Viewing application logs..."
kubectl logs -f deployment/$(APP_NAME)
status: ## Check application status
@echo "Checking application status..."
kubectl get pods -l app=$(APP_NAME)
kubectl get services -l app=$(APP_NAME)
# Security targets
security-scan: ## Run security scan
@echo "Running security scan..."
gosec ./...
@echo "Security scan complete"
# Documentation targets
docs: ## Generate documentation
@echo "Generating documentation..."
swag init -g cmd/main.go
@echo "Documentation generated"
# Dependencies
deps: ## Install dependencies
@echo "Installing dependencies..."
go mod download
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/securecodewarrior/gosec/v2/cmd/gosec@latest
go install github.com/swaggo/swag/cmd/swag@latest
@echo "Dependencies installed"// cmd/main.go
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"runtime"
"github.com/your-org/blockchain/internal/api"
"github.com/your-org/blockchain/internal/blockchain"
)
// Build-time variables (set by Makefile)
var (
Version = "dev"
BuildTime = "unknown"
GitCommit = "unknown"
)
func main() {
// Parse command line flags
port := flag.Int("port", 8080, "Server port")
configFile := flag.String("config", "config.yaml", "Configuration file")
logLevel := flag.String("log-level", "info", "Log level (debug, info, warn, error)")
flag.Parse()
// Print build information
fmt.Printf("Blockchain Application\n")
fmt.Printf("Version: %s\n", Version)
fmt.Printf("Build Time: %s\n", BuildTime)
fmt.Printf("Git Commit: %s\n", GitCommit)
fmt.Printf("Go Version: %s\n", runtime.Version())
fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
fmt.Printf("Port: %d\n", *port)
fmt.Printf("Config: %s\n", *configFile)
fmt.Printf("Log Level: %s\n", *logLevel)
// Initialize blockchain
bc := blockchain.NewBlockchain()
// Initialize API server
server := api.NewServer(bc, *port)
// Start server
log.Printf("Starting server on port %d", *port)
if err := server.Start(); err != nil && err != http.ErrServerClosed {
log.Fatalf("Server failed: %v", err)
}
}# Dockerfile for Blockchain Application
FROM golang:1.22-alpine AS builder
# Install build dependencies
RUN apk add --no-cache git ca-certificates tzdata
# Set working directory
WORKDIR /app
# Copy go mod files
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy source code
COPY . .
# Build the application
RUN CGO_ENABLED=0 GOOS=linux go build \
-ldflags "-X main.Version=$(git describe --tags --always --dirty) \
-X main.BuildTime=$(date -u '+%Y-%m-%d_%H:%M:%S') \
-X main.GitCommit=$(git rev-parse --short HEAD)" \
-a -installsuffix cgo -o main ./cmd/main.go
# Production stage
FROM alpine:latest
# Install runtime dependencies
RUN apk --no-cache add ca-certificates tzdata
# Create non-root user
RUN addgroup -g 1001 -S blockchain && \
adduser -u 1001 -S blockchain -G blockchain
# Set working directory
WORKDIR /app
# Copy binary from builder stage
COPY --from=builder /app/main .
# Copy configuration files
COPY --from=builder /app/config ./config
# Change ownership to non-root user
RUN chown -R blockchain:blockchain /app
# Switch to non-root user
USER blockchain
# Expose port
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
# Run the application
CMD ["./main"]# docker-compose.yml
version: '3.8'
services:
blockchain:
build:
context: .
dockerfile: Dockerfile
image: blockchain:latest
container_name: blockchain-app
ports:
- "8080:8080"
environment:
- LOG_LEVEL=info
- CONFIG_FILE=/app/config/config.yaml
volumes:
- ./config:/app/config
- blockchain-data:/app/data
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- blockchain-network
blockchain-db:
image: postgres:15-alpine
container_name: blockchain-db
environment:
POSTGRES_DB: blockchain
POSTGRES_USER: blockchain
POSTGRES_PASSWORD: blockchain_password
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"
restart: unless-stopped
networks:
- blockchain-network
redis:
image: redis:7-alpine
container_name: blockchain-redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
restart: unless-stopped
networks:
- blockchain-network
nginx:
image: nginx:alpine
container_name: blockchain-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/ssl:/etc/nginx/ssl
depends_on:
- blockchain
restart: unless-stopped
networks:
- blockchain-network
volumes:
blockchain-data:
postgres-data:
redis-data:
networks:
blockchain-network:
driver: bridge# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
release:
types: [ published ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [1.21, 1.22]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Install dependencies
run: go mod download
- name: Run tests
run: make test
- name: Run linter
run: make lint
- name: Run security scan
run: make security-scan
- name: Upload coverage reports
uses: codecov/codecov-action@v3
with:
file: ./coverage.out
build:
name: Build
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push' || github.event_name == 'release'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build binaries
run: make build-all
- name: Upload binaries
uses: actions/upload-artifact@v4
with:
name: binaries
path: build/bin/
deploy-dev:
name: Deploy to Development
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/develop'
environment: development
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v3
with:
version: 'latest'
- name: Configure kubectl
run: |
echo "${{ secrets.KUBE_CONFIG_DEV }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig
- name: Deploy to development
run: make deploy-dev
- name: Verify deployment
run: |
kubectl rollout status deployment/blockchain -n blockchain-dev
kubectl get pods -n blockchain-dev
deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
environment: staging
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v3
with:
version: 'latest'
- name: Configure kubectl
run: |
echo "${{ secrets.KUBE_CONFIG_STAGING }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig
- name: Deploy to staging
run: make deploy-staging
- name: Run integration tests
run: |
# Wait for deployment to be ready
kubectl rollout status deployment/blockchain -n blockchain-staging
# Run integration tests against staging
make integration-test-staging
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
needs: [build, deploy-staging]
if: github.event_name == 'release'
environment: production
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v3
with:
version: 'latest'
- name: Configure kubectl
run: |
echo "${{ secrets.KUBE_CONFIG_PROD }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig
- name: Deploy to production
run: make deploy-prod
- name: Verify production deployment
run: |
kubectl rollout status deployment/blockchain -n blockchain-prod
kubectl get pods -n blockchain-prod
- name: Run smoke tests
run: make smoke-test-prod
notify:
name: Notify
runs-on: ubuntu-latest
needs: [deploy-production]
if: always()
steps:
- name: Notify Slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#deployments'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
if: always()# k8s/prod/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: blockchain
namespace: blockchain-prod
labels:
app: blockchain
version: v1.0.0
spec:
replicas: 3
selector:
matchLabels:
app: blockchain
template:
metadata:
labels:
app: blockchain
version: v1.0.0
spec:
containers:
- name: blockchain
image: ghcr.io/your-org/blockchain:v1.0.0
ports:
- containerPort: 8080
env:
- name: LOG_LEVEL
value: "info"
- name: CONFIG_FILE
value: "/app/config/config.yaml"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: blockchain-secrets
key: database-url
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: blockchain-secrets
key: redis-url
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: config
mountPath: /app/config
readOnly: true
- name: data
mountPath: /app/data
volumes:
- name: config
configMap:
name: blockchain-config
- name: data
persistentVolumeClaim:
claimName: blockchain-pvc
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001# k8s/prod/service.yaml
apiVersion: v1
kind: Service
metadata:
name: blockchain-service
namespace: blockchain-prod
spec:
selector:
app: blockchain
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP# k8s/prod/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: blockchain-ingress
namespace: blockchain-prod
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- blockchain.yourdomain.com
secretName: blockchain-tls
rules:
- host: blockchain.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: blockchain-service
port:
number: 80#!/bin/bash
# scripts/release.sh
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Function to print colored output
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check if we're on main branch
if [[ $(git branch --show-current) != "main" ]]; then
print_error "Must be on main branch to create a release"
exit 1
fi
# Check if working directory is clean
if [[ -n $(git status --porcelain) ]]; then
print_error "Working directory is not clean. Please commit or stash changes."
exit 1
fi
# Get current version
CURRENT_VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
print_status "Current version: $CURRENT_VERSION"
# Determine release type
RELEASE_TYPE=${1:-patch}
if [[ ! "$RELEASE_TYPE" =~ ^(major|minor|patch)$ ]]; then
print_error "Release type must be major, minor, or patch"
exit 1
fi
# Calculate new version
NEW_VERSION=$(semver -i $RELEASE_TYPE $CURRENT_VERSION)
print_status "New version: $NEW_VERSION"
# Update version in files
print_status "Updating version in files..."
# Update version.go
sed -i "s/Version = \".*\"/Version = \"$NEW_VERSION\"/" cmd/main.go
# Update package.json if it exists
if [[ -f package.json ]]; then
sed -i "s/\"version\": \".*\"/\"version\": \"$NEW_VERSION\"/" package.json
fi
# Update README.md if it contains version
if [[ -f README.md ]]; then
sed -i "s/Version: .*/Version: $NEW_VERSION/" README.md
fi
# Commit version changes
git add .
git commit -m "Bump version to $NEW_VERSION"
# Create tag
print_status "Creating tag: $NEW_VERSION"
git tag -a "$NEW_VERSION" -m "Release $NEW_VERSION"
# Push changes and tag
print_status "Pushing changes and tag..."
git push origin main
git push origin "$NEW_VERSION"
# Create GitHub release
print_status "Creating GitHub release..."
gh release create "$NEW_VERSION" \
--title "Release $NEW_VERSION" \
--notes "Release $NEW_VERSION" \
--draft
print_status "Release $NEW_VERSION created successfully!"
print_status "Don't forget to:"
print_status "1. Review and publish the GitHub release"
print_status "2. Update deployment configurations"
print_status "3. Notify stakeholders"Create a comprehensive Makefile that includes:
- Build targets for multiple platforms
- Test and linting targets
- Docker build and deployment targets
- Release management targets
- Development workflow automation
Implement Docker containerization with:
- Multi-stage Dockerfile for optimized images
- Docker Compose for local development
- Health checks and monitoring
- Security best practices
- Environment-specific configurations
Set up a complete CI/CD pipeline with:
- Automated testing and linting
- Docker image building and pushing
- Multi-environment deployment
- Release automation
- Monitoring and notifications
Create Kubernetes deployment with:
- Production-ready manifests
- Resource management and scaling
- Health checks and monitoring
- Ingress and service configuration
- Secrets and configuration management
- Professional Makefile implementation
- Cross-platform build support
- Automated build processes
- Build optimization and caching
- Docker image optimization
- Multi-stage builds
- Security hardening
- Container orchestration
- Automated testing and deployment
- Multi-environment support
- Release management
- Pipeline monitoring
- Kubernetes deployment
- Production readiness
- Monitoring and health checks
- Security and compliance
blockchain/
├── cmd/
│ └── main.go
├── internal/
│ ├── blockchain/
│ ├── api/
│ └── wallet/
├── k8s/
│ ├── dev/
│ ├── staging/
│ └── prod/
├── scripts/
│ ├── release.sh
│ └── deploy.sh
├── docker/
│ └── Dockerfile
├── .github/
│ └── workflows/
├── Makefile
├── docker-compose.yml
├── go.mod
└── go.sum
- Set up the build environment
- Create the Makefile
- Implement Docker containerization
- Set up CI/CD pipeline
- Configure Kubernetes deployment
- Test the complete deployment process
- "Docker in Action" by Jeff Nickoloff
- "Kubernetes in Action" by Marko Lukša
- "Continuous Delivery" by Jez Humble
- "The Phoenix Project" by Gene Kim
- Make: Build automation
- Docker: Containerization
- Kubernetes: Container orchestration
- GitHub Actions: CI/CD automation
- Helm: Kubernetes package manager
- Docker Documentation: Official Docker guides
- Kubernetes Documentation: Official K8s guides
- GitHub Actions: CI/CD tutorials
- Make Tutorial: Makefile best practices
- Create professional Makefile
- Implement cross-platform builds
- Set up Docker containerization
- Configure CI/CD pipeline
- Deploy to Kubernetes
- Implement release management
- Set up monitoring and health checks
- Test complete deployment process
- Document deployment procedures
- Optimize build and deployment performance
Ready to build professional deployment systems? Let's start implementing robust build and deployment strategies! 🚀