1.编写简单的go程序
cd /home
mkdir docker-go-test
cd docker-go-test
vi go-web-test.go
go-web-test.go:
package main
import (
"log"
"net/http"
)
func sayHello(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(r.Host +" : hello world"))
}
func main() {
http.HandleFunc("/", sayHello)
log.Println("服务启动成功 监听端口:8050")
err := http.ListenAndServe("0.0.0.0:8050", nil)
if err != nil {
log.Fatal("ListenAndServe Err: ", err)
}
}
2.编写Dokerfile
vi Dockerfile
Dockerfile:
FROM golang:latest
WORKDIR $GOPATH/src/docker-go-test
COPY . $GOPATH/src/docker-go-test
# 交叉编译 :此处编译为linux版本 go程序
# GOOS=darwin 为mac版本 GOOS=windows 为windows版本
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o go-web-test go-web-test.go
EXPOSE 8050
ENTRYPOINT ["./go-web-test"]
3.生成docker镜像
docker build -t docker-go-test .
生成镜像如下:
4.测试docker-go-test镜像
docker run -d -p 8050:8050 --name go-test docker-go-test
进入容器可查看到第2步Dockerfile操作的内容
访问测试:
5.docker-compose编排多个相同go服务
vi docker-compose.yml
version: '2'
services:
go-test01:
container_name: go-test01
build:
# context设定上下文跟目录,以此目录指定Dockerfile
context: ./
dockerfile: Dockerfile
ports:
- "9010:8050"
go-test02:
container_name: go-test02
build:
context: ./
dockerfile: Dockerfile
ports:
- "9020:8050"
go-test03:
container_name: go-test03
build:
context: ./
dockerfile: Dockerfile
ports:
- "9030:8050"
6.启动docker-compose
docker-compose up -d
访问测试:
7. docker-compose 编排 nginx + go-test实现负载均衡
7.1 准备nginx.conf与default.conf文件 以便挂载
cd /home/docker-go-test
# 创建用于挂载nginx配置文件的目录
mkdir -p conf/conf.d
cd conf
vi nginx.conf
nginx.conf
#定义Nginx运行的用户和用户组
user nginx;
#nginx进程数,建议设置为等于CPU总核心数
worker_processes 1;
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log warn;
#进程文件
pid /var/run/nginx.pid;
#工作模式与连接数上限
events {
#单个进程最大连接数(最大连接数=连接数*进程数)
worker_connections 1024;
}
#设定http服务器
http {
#文件扩展名与文件类型映射表
include /etc/nginx/mime.types;
#默认文件类型
default_type application/octet-stream;
#日志的格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#全局访问日志
access_log /var/log/nginx/access.log main;
#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处
理速度,降低系统的负载。注意:如果图片显示不正常把这个改 成off。
sendfile on;
#防止网络阻塞
#tcp_nopush on;
#长连接超时时间,单位是秒
keepalive_timeout 65;
#开启gzip压缩输出
#gzip on;
#负载均衡(权重轮询)
upstream go-test {
server go-test01:8050 weight=1;
server go-test02:8050 weight=2;
server go-test03:8050 weight=3;
}
#虚拟主机的配置
include /etc/nginx/conf.d/*.conf;
}
cd conf.d
vi default.conf
server{
listen 80;
location / {
# 反向代理
proxy_set_header Host $http_host;
proxy_set_header X-Forward-For $remote_addr;
proxy_set_header X-real-ip $remote_addr;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
proxy_pass http://go-test;
}
}
7.2 修改go-web-test.go文件
package main
import (
"errors"
"log"
"net"
"net/http"
"strings"
)
func sayHello(w http.ResponseWriter, r *http.Request) {
// 获取内网ip 以便区分是nginx反向代理请求是哪个go-test服务处理的
ip, err := GetInternalIP()
if err != nil {
log.Fatal("GET IP Err: ", err)
}
w.Write([]byte("GetInternalIP: " + ip + "\n"))
w.Write([]byte(r.Host + " : hello world"))
}
func main() {
http.HandleFunc("/", sayHello)
log.Println("服务启动成功 监听端口:8050")
err := http.ListenAndServe("0.0.0.0:8050", nil)
if err != nil {
log.Fatal("ListenAndServe Err: ", err)
}
}
func GetInternalIP() (string, error) {
// 思路来自于Python版本的内网IP获取,其他版本不准确
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
return "", errors.New("internal IP fetch failed, detail:" + err.Error())
}
defer conn.Close()
// udp 面向无连接,所以这些东西只在你本地捣鼓
res := conn.LocalAddr().String()
res = strings.Split(res, ":")[0]
return res, nil
}
7.3 docker-compose 编排 nginx + go-test
docker-compose.yml
go-test01,go-test02,go-test03对宿主机开放的端口被注释,无法通过 宿主机IP:端口方式访问了
nginx开放了对宿主机的9050端口,通过nginx.conf与default.conf文件实现反向代理,负载均衡
version: '2'
services:
nginx:
image: nginx
container_name: go-test-nginx
# 挂载宿主机端口9050
ports:
- "9050:80"
volumes:
# 挂载nginx目录
- /home/docker-go-test/www:/usr/share/nginx/html/
# 挂载nginx日志
- /home/docker-go-test/log:/var/log/nginx/
# 挂载nginx配置文件
- /home/docker-go-test/conf/nginx.conf:/etc/nginx/nginx.conf
# 挂载虚拟主机配置文件
- /home/docker-go-test/conf/conf.d/default.conf:/etc/nginx/conf.d/default.conf
go-test01:
container_name: go-test01
build:
# context设定上下文跟目录,以此目录指定Dockerfile
context: ./
dockerfile: Dockerfile
# ports:
# - "9010:8050"
go-test02:
container_name: go-test02
build:
context: ./
dockerfile: Dockerfile
# ports:
# - "9020:8050"
go-test03:
container_name: go-test03
build:
context: ./
dockerfile: Dockerfile
# ports:
# - "9030:8050"
7.4 确认docker-compose创建的网络
# 查看docker所有网络
docker network ls
# 查看docker-compose创建的docker-go-test_default网络
docker network inspect docker-go-test_default
go-test01:172.31.0.2
go-test02:172.31.0.5
go-test03:172.31.0.3
go-test-nginx:172.31.0.4
7.5 访问测试
http://宿主机ip:9050/
nginx负载均衡如下图所示:
8. nginx 负载均衡策略
8.1 轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
upstream go-test {
server go-test01:8050;
server go-test02:8050;
server go-test03:8050;
}
8.2 权重轮询
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的
upstream go-test {
server go-test01:8050 weight=1;
server go-test02:8050 weight=2;
server go-test03:8050 weight=3;
}
8.3 ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题
upstream go-test {
ip_hash;
server go-test01:8050;
server go-test02:8050;
server go-test03:8050;
}
8.4 least_conn 最少连接
连接最少的;最少连接允许在某些请求需要较长时间才能完成的情况下更公平地控制应用程序实例上的负载.
upstream go-test {
least_conn;
server go-test01:8050;
server go-test02:8050;
server go-test03:8050;
}
每次修改负载均衡策略后 可重启go-test-nginx容器测试:
docker restart go-test-nginx