Overview
This example shows how to containerize and deploy a web service using Buildr. You’ll learn how to expose ports, configure replicas for scaling, and make your service publicly accessible.
Complete Example
Here’s a complete HTTP server that’s automatically containerized and deployed:
#!/usr/bin/python
from six.moves import SimpleHTTPServer, socketserver
import socket
from metaparticle_pkg.containerize import Containerize
OK = 200
port = 8080
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(OK)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write("Hello Metaparticle [{}] @ {}\n".format(self.path, socket.gethostname()).encode('UTF-8'))
print("request for {}".format(self.path))
def do_HEAD(self):
self.send_response(OK)
self.send_header("Content-type", "text/plain")
self.end_headers()
@Containerize(
package={'name': 'web', 'repository': 'docker.io/brendanburns'},
runtime={'ports': [8080], 'executor': 'metaparticle', 'replicas': 3, 'public': True}
)
def main():
Handler = MyHandler
httpd = socketserver.TCPServer(("", port), Handler)
httpd.serve_forever()
if __name__ == '__main__':
main()
Step-by-Step Breakdown
Import dependencies
from six.moves import SimpleHTTPServer, socketserver
import socket
from metaparticle_pkg.containerize import Containerize
- SimpleHTTPServer: Basic HTTP server implementation
- socketserver: TCP server framework
- socket: For getting hostname information
- Containerize: Buildr decorator for containerization
Create HTTP request handler
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(OK)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write("Hello Metaparticle [{}] @ {}\n".format(
self.path, socket.gethostname()).encode('UTF-8'))
print("request for {}".format(self.path))
Custom handler that:
- Responds to GET requests with a 200 OK status
- Returns the requested path and hostname
- Shows which container instance handled the request
The hostname in the response helps you see load balancing across replicas in action!
Configure containerization with scaling
@Containerize(
package={'name': 'web', 'repository': 'docker.io/brendanburns'},
runtime={
'ports': [8080],
'executor': 'metaparticle',
'replicas': 3,
'public': True
}
)
def main():
Handler = MyHandler
httpd = socketserver.TCPServer(("", port), Handler)
httpd.serve_forever()
This configuration does several important things:Package Configuration:
- name:
'web' - The container image name
- repository:
'docker.io/brendanburns' - Docker Hub repository
Runtime Configuration:
- ports:
[8080] - Exposes port 8080 for HTTP traffic
- executor:
'metaparticle' - Uses Metaparticle runtime for orchestration
- replicas:
3 - Runs 3 instances of the service for load balancing
- public:
True - Makes the service accessible from outside the cluster
Start the server
if __name__ == '__main__':
main()
When executed, Buildr will:
- Build a Docker image containing your web service
- Deploy 3 replicas to the Metaparticle runtime
- Configure load balancing across all replicas
- Expose the service publicly on port 8080
Configuration Options Explained
Package Options
| Option | Type | Description | Example |
|---|
name | string | Service/image name | 'web' |
repository | string | Docker registry repository | 'docker.io/yourusername' |
Runtime Options
| Option | Type | Description | Default |
|---|
ports | array | Ports to expose | [] |
executor | string | Runtime executor (docker, metaparticle) | 'docker' |
replicas | number | Number of instances to run | 1 |
public | boolean | Make service publicly accessible | false |
The metaparticle executor provides orchestration features like replicas and load balancing. Use docker executor for simple local testing.
Running the Example
Save the code
Save the example to web.py
Run the service
Buildr will build, deploy, and start your service with 3 replicas. Test the service
curl http://localhost:8080/hello
You’ll see responses from different container instances:Hello Metaparticle [/hello] @ web-abc123
Hello Metaparticle [/hello] @ web-def456
Hello Metaparticle [/hello] @ web-ghi789
Scaling Your Service
Buildr makes it easy to scale your web service by adjusting the replicas configuration:
# Single instance for development
runtime={'replicas': 1, 'public': False}
# 3 replicas for production
runtime={'replicas': 3, 'public': True}
# High availability with 10 replicas
runtime={'replicas': 10, 'public': True}
Start with fewer replicas during development and increase them in production based on your traffic patterns and performance requirements.
Load Balancing
When you set replicas > 1, Buildr automatically:
- Distributes traffic across all container instances
- Health checks each replica to ensure availability
- Routes requests to healthy instances only
- Balances load using round-robin or other algorithms
Public vs Private Services
Public Service (public: True)
- Accessible from the internet
- Gets an external IP or load balancer
- Suitable for customer-facing applications
Private Service (public: False)
- Only accessible within the cluster
- No external exposure
- Suitable for internal microservices
# Public-facing API
@Containerize(
package={'name': 'api', 'repository': 'myrepo'},
runtime={'ports': [80], 'public': True, 'replicas': 5}
)
# Internal service
@Containerize(
package={'name': 'worker', 'repository': 'myrepo'},
runtime={'public': False, 'replicas': 2}
)
Best Practices
Use appropriate replica counts
- Development: 1 replica
- Staging: 2-3 replicas
- Production: 3+ replicas (odd numbers for quorum-based systems)
Configure health checks
Implement health check endpoints:def do_GET(self):
if self.path == '/health':
self.send_response(200)
self.end_headers()
return
# ... normal request handling
Use environment-specific repositories
import os
repo = os.getenv('DOCKER_REPO', 'docker.io/myuser')