mirror of
https://github.com/bingohuang/docker-labs.git
synced 2025-07-14 10:17:26 +08:00
parent
7df7a7c68f
commit
a4b0a98df3
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,3 @@
|
|||||||
play-with-docker
|
play-with-docker
|
||||||
node_modules
|
node_modules
|
||||||
|
pwd/*
|
||||||
|
@ -2,12 +2,17 @@ package config
|
|||||||
|
|
||||||
import "flag"
|
import "flag"
|
||||||
|
|
||||||
var SSLPortNumber, PortNumber, Key, Cert string
|
var SSLPortNumber, PortNumber, Key, Cert, SessionsFile, PWDContainerName, PWDCName string
|
||||||
|
var MaxLoadAvg float64
|
||||||
|
|
||||||
func ParseFlags() {
|
func ParseFlags() {
|
||||||
flag.StringVar(&PortNumber, "port", "3000", "Give a TCP port to run the application")
|
flag.StringVar(&PortNumber, "port", "3000", "Give a TCP port to run the application")
|
||||||
flag.StringVar(&SSLPortNumber, "sslPort", "3001", "Give a SSL TCP port")
|
flag.StringVar(&SSLPortNumber, "sslPort", "3001", "Give a SSL TCP port")
|
||||||
flag.StringVar(&Key, "key", "./pwd/server-key.pem", "Server key for SSL")
|
flag.StringVar(&Key, "key", "./pwd/server-key.pem", "Server key for SSL")
|
||||||
flag.StringVar(&Cert, "cert", "./pwd/server.pem", "Give a SSL cert")
|
flag.StringVar(&Cert, "cert", "./pwd/server.pem", "Give a SSL cert")
|
||||||
|
flag.StringVar(&SessionsFile, "save", "./pwd/sessions", "Tell where to store sessions file")
|
||||||
|
flag.StringVar(&PWDContainerName, "name", "pwd", "Container name used to run PWD (used to be able to connect it to the networks it creates)")
|
||||||
|
flag.StringVar(&PWDCName, "cname", "host1", "CNAME given to this host")
|
||||||
|
flag.Float64Var(&MaxLoadAvg, "maxload", 100, "Maximum allowed load average before failing ping requests")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,35 @@
|
|||||||
version: '2'
|
version: '2'
|
||||||
services:
|
services:
|
||||||
pwd:
|
haproxy:
|
||||||
|
container_name: proxy
|
||||||
|
image: haproxy
|
||||||
|
ports:
|
||||||
|
- "80:8080"
|
||||||
|
- "443:8443"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- ./haproxy:/usr/local/etc/haproxy
|
||||||
|
pwd1:
|
||||||
# pwd daemon container always needs to be named this way
|
# pwd daemon container always needs to be named this way
|
||||||
container_name: pwd
|
container_name: pwd1
|
||||||
# use the latest golang image
|
# use the latest golang image
|
||||||
image: golang
|
image: golang
|
||||||
# go to the right place and starts the app
|
# go to the right place and starts the app
|
||||||
command: /bin/sh -c 'cd /go/src/github.com/franela/play-with-docker; go run api.go'
|
command: /bin/sh -c 'cd /go/src/github.com/franela/play-with-docker; go run api.go -save ./pwd/sessions1 -name pwd1 -cname host1'
|
||||||
ports:
|
volumes:
|
||||||
# app exposes port 3000
|
# since this app creates networks and launches containers, we need to talk to docker daemon
|
||||||
- "80:3000"
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- "443:3001"
|
# mount the box mounted shared folder to the container
|
||||||
|
- $GOPATH/src:/go/src
|
||||||
|
environment:
|
||||||
|
GOOGLE_RECAPTCHA_DISABLED: "true"
|
||||||
|
pwd2:
|
||||||
|
# pwd daemon container always needs to be named this way
|
||||||
|
container_name: pwd2
|
||||||
|
# use the latest golang image
|
||||||
|
image: golang
|
||||||
|
# go to the right place and starts the app
|
||||||
|
command: /bin/sh -c 'cd /go/src/github.com/franela/play-with-docker; go run api.go -save ./pwd/sessions2 -name pwd2 -cname host2'
|
||||||
volumes:
|
volumes:
|
||||||
# since this app creates networks and launches containers, we need to talk to docker daemon
|
# since this app creates networks and launches containers, we need to talk to docker daemon
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
@ -2,7 +2,6 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/franela/play-with-docker/services"
|
"github.com/franela/play-with-docker/services"
|
||||||
@ -12,7 +11,6 @@ import (
|
|||||||
func GetSession(rw http.ResponseWriter, req *http.Request) {
|
func GetSession(rw http.ResponseWriter, req *http.Request) {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
sessionId := vars["sessionId"]
|
sessionId := vars["sessionId"]
|
||||||
log.Println(sessionId)
|
|
||||||
|
|
||||||
session := services.GetSession(sessionId)
|
session := services.GetSession(sessionId)
|
||||||
|
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/franela/play-with-docker/config"
|
||||||
"github.com/franela/play-with-docker/services"
|
"github.com/franela/play-with-docker/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type NewSessionResponse struct {
|
||||||
|
SessionId string `json:"session_id"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
}
|
||||||
|
|
||||||
func NewSession(rw http.ResponseWriter, req *http.Request) {
|
func NewSession(rw http.ResponseWriter, req *http.Request) {
|
||||||
req.ParseForm()
|
req.ParseForm()
|
||||||
if !services.IsHuman(req) {
|
if !services.IsHuman(req) {
|
||||||
@ -25,11 +32,15 @@ func NewSession(rw http.ResponseWriter, req *http.Request) {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
//TODO: Return some error code
|
//TODO: Return some error code
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
hostname := fmt.Sprintf("%s.%s", config.PWDCName, req.Host)
|
||||||
// If request is not a form, return sessionId in the body
|
// If request is not a form, return sessionId in the body
|
||||||
if req.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
if req.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||||
rw.Write([]byte(s.Id))
|
resp := NewSessionResponse{SessionId: s.Id, Hostname: hostname}
|
||||||
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(rw).Encode(resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(rw, req, fmt.Sprintf("/p/%s", s.Id), http.StatusFound)
|
http.Redirect(rw, req, fmt.Sprintf("http://%s/p/%s", hostname, s.Id), http.StatusFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,23 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/franela/play-with-docker/config"
|
||||||
|
"github.com/shirou/gopsutil/load"
|
||||||
|
)
|
||||||
|
|
||||||
func Ping(rw http.ResponseWriter, req *http.Request) {
|
func Ping(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
// Get system load average of the last 5 minutes and compare it against a threashold.
|
||||||
|
|
||||||
|
a, err := load.Avg()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Cannot get system load average!", err)
|
||||||
|
} else {
|
||||||
|
if a.Load5 > config.MaxLoadAvg {
|
||||||
|
log.Printf("System load average is too high [%f]\n", a.Load5)
|
||||||
|
rw.WriteHeader(http.StatusInsufficientStorage)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
32
haproxy/haproxy.cfg
Normal file
32
haproxy/haproxy.cfg
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
defaults
|
||||||
|
mode http
|
||||||
|
timeout connect 5000ms
|
||||||
|
timeout client 50000ms
|
||||||
|
timeout server 50000ms
|
||||||
|
|
||||||
|
frontend http-in
|
||||||
|
bind *:8080
|
||||||
|
|
||||||
|
acl host_localhost hdr(host) localhost
|
||||||
|
acl host_pwd1 hdr_reg(host) -i ^.*\.?host1\.localhost$
|
||||||
|
acl host_pwd2 hdr_reg(host) -i ^.*\.?host2\.localhost$
|
||||||
|
|
||||||
|
use_backend all if host_localhost
|
||||||
|
use_backend pwd1 if host_pwd1
|
||||||
|
use_backend pwd2 if host_pwd2
|
||||||
|
|
||||||
|
backend all
|
||||||
|
balance roundrobin
|
||||||
|
|
||||||
|
option httpchk GET /ping HTTP/1.0
|
||||||
|
http-check expect rstatus 200
|
||||||
|
default-server inter 3s fall 3 rise 2
|
||||||
|
|
||||||
|
server node1 pwd1:3000 check
|
||||||
|
server node2 pwd2:3000 check
|
||||||
|
|
||||||
|
backend pwd1
|
||||||
|
server node1 pwd1:3000
|
||||||
|
|
||||||
|
backend pwd2
|
||||||
|
server node2 pwd2:3000
|
1
pwd/.gitignore
vendored
1
pwd/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
sessions.gob
|
|
@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/api"
|
"github.com/docker/docker/api"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
"github.com/franela/play-with-docker/config"
|
||||||
"github.com/googollee/go-socket.io"
|
"github.com/googollee/go-socket.io"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/twinj/uuid"
|
"github.com/twinj/uuid"
|
||||||
@ -241,13 +242,13 @@ func NewSession(duration time.Duration) (*Session, error) {
|
|||||||
log.Printf("Network [%s] created for session [%s]\n", s.Id, s.Id)
|
log.Printf("Network [%s] created for session [%s]\n", s.Id, s.Id)
|
||||||
|
|
||||||
// Connect PWD daemon to the new network
|
// Connect PWD daemon to the new network
|
||||||
ip, err := ConnectNetwork("pwd", s.Id, "")
|
ip, err := ConnectNetwork(config.PWDContainerName, s.Id, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("ERROR NETWORKING")
|
log.Println("ERROR NETWORKING")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.PwdIpAddress = ip
|
s.PwdIpAddress = ip
|
||||||
log.Printf("Connected pwd to network [%s]\n", s.Id)
|
log.Printf("Connected %s to network [%s]\n", config.PWDContainerName, s.Id)
|
||||||
|
|
||||||
// Schedule peridic tasks execution
|
// Schedule peridic tasks execution
|
||||||
s.SchedulePeriodicTasks()
|
s.SchedulePeriodicTasks()
|
||||||
@ -290,7 +291,7 @@ func setGauges() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LoadSessionsFromDisk() error {
|
func LoadSessionsFromDisk() error {
|
||||||
file, err := os.Open("./pwd/sessions.gob")
|
file, err := os.Open(config.SessionsFile)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
decoder := gob.NewDecoder(file)
|
decoder := gob.NewDecoder(file)
|
||||||
err = decoder.Decode(&sessions)
|
err = decoder.Decode(&sessions)
|
||||||
@ -322,7 +323,7 @@ func LoadSessionsFromDisk() error {
|
|||||||
if s.PwdIpAddress == "" {
|
if s.PwdIpAddress == "" {
|
||||||
log.Fatal("Cannot load stored sessions as they don't have the pwd ip address stored with them")
|
log.Fatal("Cannot load stored sessions as they don't have the pwd ip address stored with them")
|
||||||
}
|
}
|
||||||
if _, err := ConnectNetwork("pwd", s.Id, s.PwdIpAddress); err != nil {
|
if _, err := ConnectNetwork(config.PWDContainerName, s.Id, s.PwdIpAddress); err != nil {
|
||||||
if strings.Contains(err.Error(), "Could not attach to network") {
|
if strings.Contains(err.Error(), "Could not attach to network") {
|
||||||
log.Printf("Network for session [%s] doesn't exist. Removing all instances and session.", s.Id)
|
log.Printf("Network for session [%s] doesn't exist. Removing all instances and session.", s.Id)
|
||||||
CloseSession(s)
|
CloseSession(s)
|
||||||
@ -331,7 +332,7 @@ func LoadSessionsFromDisk() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Connected pwd to network [%s]\n", s.Id)
|
log.Printf("Connected %s to network [%s]\n", config.PWDContainerName, s.Id)
|
||||||
|
|
||||||
// Schedule peridic tasks execution
|
// Schedule peridic tasks execution
|
||||||
s.SchedulePeriodicTasks()
|
s.SchedulePeriodicTasks()
|
||||||
@ -346,7 +347,7 @@ func LoadSessionsFromDisk() error {
|
|||||||
func saveSessionsToDisk() error {
|
func saveSessionsToDisk() error {
|
||||||
rw.Lock()
|
rw.Lock()
|
||||||
defer rw.Unlock()
|
defer rw.Unlock()
|
||||||
file, err := os.Create("./pwd/sessions.gob")
|
file, err := os.Create(config.SessionsFile)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
encoder := gob.NewEncoder(file)
|
encoder := gob.NewEncoder(file)
|
||||||
err = encoder.Encode(&sessions)
|
err = encoder.Encode(&sessions)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user