Skip to content

Commit

Permalink
1, Fix the risk of the container being accidentally deleted due to th…
Browse files Browse the repository at this point in the history
…e global containerid variable.\r\n2,If the bridge mode is created when the container is created, when no port is specified, the port set by `EXPOSE` in the Dockerfile is automatically mapped.
  • Loading branch information
bobliu0909 committed Oct 13, 2018
1 parent c704047 commit 8404cfb
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 55 deletions.
7 changes: 3 additions & 4 deletions conf/app.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
appname = humpback-agent
httpport = 8500
runmode = dev
autorender = false
copyrequestbody = true
Expand All @@ -11,13 +10,13 @@ DOCKER_REGISTRY_ADDRESS = http://192.168.2.80
ENABLE_BUILD_IMAGE = false
DOCKER_COMPOSE_PATH = ./compose_files
DOCKER_COMPOSE_PACKAGE_MAXSIZE = 67108864
DOCKER_AGENT_IPADDR = 0.0.0.0
DOCKER_NODE_HTTPADDR = 0.0.0.0:8500
DOCKER_CONTAINER_PORTS_RANGE = 8000-8999
DOCKER_CLUSTER_ENABLED = false
DOCKER_CLUSTER_URIS = zk://192.168.2.80:2181,192.168.2.81:2181,192.168.2.82:2181
DOCKER_CLUSTER_NAME = humpback/center
DOCKER_CLUSTER_HEARTBEAT = 8s
DOCKER_CLUSTER_TTL = 30s
DOCKER_CLUSTER_PORTS_RANGE = 8000-8999
DOCKER_CLUSTER_TTL = 30s
LOG_LEVEL = 3
; 0 - LevelEmergency
; 1 - LevelAlert
Expand Down
63 changes: 50 additions & 13 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package config

import "github.com/humpback/common/models"
import "github.com/astaxie/beego"
import "github.com/humpback/common/models"
import "github.com/humpback/gounits/network"

import (
"fmt"
"net"
"os"
"strconv"
"strings"
)

var config *models.Config
Expand All @@ -27,10 +31,14 @@ func Init() {
envRegistryAddr = beego.AppConfig.DefaultString("DOCKER_REGISTRY_ADDRESS", "docker.neg")
}

//若没有设置环境变量, 默认(0.0.0.0)时,则在节点注册时自动获取一个本机地址.
envAgentIPAddr := os.Getenv("DOCKER_AGENT_IPADDR")
if envAgentIPAddr == "" {
envAgentIPAddr = beego.AppConfig.DefaultString("DOCKER_AGENT_IPADDR", "0.0.0.0")
envNodeHTTPAddr := os.Getenv("DOCKER_NODE_HTTPADDR")
if envNodeHTTPAddr == "" {
envNodeHTTPAddr = beego.AppConfig.DefaultString("DOCKER_NODE_HTTPADDR", "0.0.0.0:8500")
}

envContainerPortsRange := os.Getenv("DOCKER_CONTAINER_PORTS_RANGE")
if envContainerPortsRange == "" {
envContainerPortsRange = beego.AppConfig.DefaultString("DOCKER_CONTAINER_PORTS_RANGE", "0-0")
}

var envEnableBuildImg bool
Expand Down Expand Up @@ -91,11 +99,6 @@ func Init() {
envClusterTTL = beego.AppConfig.DefaultString("DOCKER_CLUSTER_TTL", "35s")
}

envClusterPortsRange := os.Getenv("DOCKER_CLUSTER_PORTS_RANGE")
if envClusterPortsRange == "" {
envClusterPortsRange = beego.AppConfig.DefaultString("DOCKER_CLUSTER_PORTS_RANGE", "0-0")
}

var logLevel int
if envLogLevel := os.Getenv("LOG_LEVEL"); envLogLevel != "" {
logLevel, _ = strconv.Atoi(envLogLevel)
Expand All @@ -110,13 +113,13 @@ func Init() {
EnableBuildImage: envEnableBuildImg,
DockerComposePath: envComposePath,
DockerComposePackageMaxSize: envComposePackageMaxSize,
DockerAgentIPAddr: envAgentIPAddr,
DockerNodeHTTPAddr: envNodeHTTPAddr,
DockerContainerPortsRange: envContainerPortsRange,
DockerClusterEnabled: envClusterEnabled,
DockerClusterURIs: envClusterURIs,
DockerClusterName: envClusterName,
DockerClusterHeartBeat: envClusterHeartBeat,
DockerClusterTTL: envClusterTTL,
DockerClusterPortsRange: envClusterPortsRange,
LogLevel: logLevel,
}
}
Expand All @@ -126,7 +129,41 @@ func GetConfig() models.Config {
return *config
}

// SetAppVersion - ser app version
// SetVersion - set app version
func SetVersion(version string) {
config.AppVersion = version
}

// GetNodeHTTPAddrIPPort - return local agent httpaddr info
func GetNodeHTTPAddrIPPort() (string, int, error) {

httpAddr := strings.TrimSpace(config.DockerNodeHTTPAddr)
if strings.Index(httpAddr, ":") < 0 {
httpAddr = httpAddr + ":"
}

pAddrStr := strings.SplitN(httpAddr, ":", 2)
if pAddrStr[1] == "" {
httpAddr = httpAddr + "8500"
}

strHost, strPort, err := net.SplitHostPort(httpAddr)
if err != nil {
return "", 0, err
}

if strHost == "" || strHost == "0.0.0.0" {
strHost = network.GetDefaultIP()
}

ip := net.ParseIP(strHost)
if ip == nil {
return "", 0, fmt.Errorf("httpAddr ip invalid")
}

port, err := strconv.Atoi(strPort)
if err != nil || port > 65535 || port <= 0 {
return "", 0, fmt.Errorf("httpAddr port invalid")
}
return ip.String(), port, nil
}
77 changes: 48 additions & 29 deletions controllers/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,16 @@ type containerError struct {
Error error
}

var containerID string
var clientTimeout = 30 * time.Second

// Prepare - format path before exec real action
func (ctCtrl *ContainerController) Prepare() {
containerID = ctCtrl.Ctx.Input.Param(":containerid")
}

// GetContainer - get container info with name or id
func (ctCtrl *ContainerController) GetContainer() {
var container models.Container
containerID := ctCtrl.Ctx.Input.Param(":containerid")
originalContainer, err := dockerClient.ContainerInspect(context.Background(), containerID)
if err != nil {
if strings.Index(err.Error(), "No such container") != -1 {
Expand Down Expand Up @@ -72,7 +71,6 @@ func (ctCtrl *ContainerController) GetContainers() {
// GetContainerLogs - get container
func (ctCtrl *ContainerController) GetContainerLogs() {
tail := ctCtrl.GetString("tail")

since := ctCtrl.Ctx.Input.Query("since")
if since != "" {
tempTime, err := time.Parse("2006-01-02", since)
Expand All @@ -91,6 +89,8 @@ func (ctCtrl *ContainerController) GetContainerLogs() {
if tail != "" {
option.Tail = tail
}

containerID := ctCtrl.Ctx.Input.Param(":containerid")
res, err := dockerClient.ContainerLogs(context.Background(), containerID, option)
if err != nil {
ctCtrl.Error(500, err.Error())
Expand Down Expand Up @@ -183,6 +183,7 @@ func getContainerStats(name string, id string, ch chan models.ContainerStatsWith

// GetContainerStats - get container's stats, include (cpu/memory/network...)
func (ctCtrl *ContainerController) GetContainerStats() {
containerID := ctCtrl.Ctx.Input.Param(":containerid")
container, err := dockerClient.ContainerInspect(context.Background(), containerID)
if err != nil {
if strings.Index(err.Error(), "No such container") != -1 {
Expand All @@ -207,6 +208,7 @@ func (ctCtrl *ContainerController) GetContainerStats() {

// GetContainerStatus - get container's status (running, paused, restarting, killed, dead, pid, exitcode...)
func (ctCtrl *ContainerController) GetContainerStatus() {
containerID := ctCtrl.Ctx.Input.Param(":containerid")
container, err := dockerClient.ContainerInspect(context.Background(), containerID)
if err != nil {
if strings.Index(err.Error(), "No such container") != -1 {
Expand Down Expand Up @@ -247,7 +249,8 @@ func (ctCtrl *ContainerController) CreateContainer() {
}

// determine whether there is a image
if err := tryPullImage(reqBody.Image); err != nil {
inspectImage, err := tryPullImage(reqBody.Image)
if err != nil {
ctCtrl.Error(500, err.Error(), 21001)
}

Expand Down Expand Up @@ -298,27 +301,47 @@ func (ctCtrl *ContainerController) CreateContainer() {
//port binding
config.ExposedPorts = make(nat.PortSet)
portBinding := make(nat.PortMap)
for _, item := range reqBody.Ports {
privatePort := nat.Port(strconv.Itoa(item.PrivatePort) + "/" + item.Type)
config.ExposedPorts[privatePort] = *new(struct{})
if item.PublicPort != 0 {
tempPublicPort := []nat.PortBinding{
nat.PortBinding{
HostIP: item.IP,
HostPort: strconv.Itoa(item.PublicPort),
},
if hostconfig.NetworkMode.IsBridge() {
if len(reqBody.Ports) > 0 {
hostconfig.PublishAllPorts = false //disable -P ports alloc.
for _, item := range reqBody.Ports {
privatePort := nat.Port(strconv.Itoa(item.PrivatePort) + "/" + item.Type)
config.ExposedPorts[privatePort] = *new(struct{})
if item.PublicPort != 0 {
tempPublicPort := []nat.PortBinding{
nat.PortBinding{
HostIP: item.IP,
HostPort: strconv.Itoa(item.PublicPort),
},
}
portBinding[privatePort] = tempPublicPort
} else {
hostPort := ctCtrl.makeSystemIdlePort(item.Type)
if hostPort > 0 {
tempPublicPort := []nat.PortBinding{
nat.PortBinding{
HostIP: item.IP,
HostPort: strconv.Itoa((int)(hostPort)),
},
}
portBinding[privatePort] = tempPublicPort
}
}
}
portBinding[privatePort] = tempPublicPort
} else {
hostPort := ctCtrl.makeSystemIdlePort(item.Type)
if hostPort > 0 {
tempPublicPort := []nat.PortBinding{
nat.PortBinding{
HostIP: item.IP,
HostPort: strconv.Itoa((int)(hostPort)),
},
for item := range inspectImage.Config.ExposedPorts {
privatePort := item
config.ExposedPorts[privatePort] = *new(struct{})
hostPort := ctCtrl.makeSystemIdlePort(item.Proto())
if hostPort > 0 {
tempPublicPort := []nat.PortBinding{
nat.PortBinding{
HostIP: "0.0.0.0",
HostPort: strconv.Itoa((int)(hostPort)),
},
}
portBinding[privatePort] = tempPublicPort
}
portBinding[privatePort] = tempPublicPort
}
}
}
Expand Down Expand Up @@ -437,6 +460,7 @@ func (ctCtrl *ContainerController) OperateContainer() {
// DeleteContainer - delete container
func (ctCtrl *ContainerController) DeleteContainer() {

containerID := ctCtrl.Ctx.Input.Param(":containerid")
ctx, cancel := context.WithTimeout(context.Background(), clientTimeout)
removeCh := make(chan containerError, 1)
var err error
Expand Down Expand Up @@ -481,8 +505,7 @@ func upgradeContainer(id, newTag string) (string, int, error) {
newImage := strings.Split(container.Config.Image, ":")[0] + ":" + newTag

beego.Debug("UPGRADE - Begin try to pull image " + newImage)
err = tryPullImage(newImage)
fmt.Println(err)
_, err = tryPullImage(newImage)
if err != nil {
return "", 20004, err
}
Expand Down Expand Up @@ -565,11 +588,7 @@ func (ctCtrl *ContainerController) makeSystemIdlePort(kind string) int {
)

conf := config.GetConfig()
if !conf.DockerClusterEnabled {
return 0
}

rangePorts := strings.SplitN(conf.DockerClusterPortsRange, "-", 2)
rangePorts := strings.SplitN(conf.DockerContainerPortsRange, "-", 2)
if len(rangePorts) != 2 {
return 0
}
Expand Down
19 changes: 13 additions & 6 deletions controllers/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (imgCtrl *ImageController) PullImage() {
if reqBody.Image == "" {
imgCtrl.Error(400, "Image name cannot be empty or null.")
}
err := tryPullImage(reqBody.Image)
_, err := tryPullImage(reqBody.Image)
if err != nil {
imgCtrl.Error(500, err.Error())
}
Expand Down Expand Up @@ -86,8 +86,14 @@ func (imgCtrl *ImageController) DeleteImage() {
}

// tryPullImage - if image is exists then return or pull it from registry
func tryPullImage(imageID string) error {
_, _, inspectErr := dockerClient.ImageInspectWithRaw(context.Background(), imageID)
func tryPullImage(imageID string) (types.ImageInspect, error) {

var (
inspectInfo types.ImageInspect
inspectErr error
)

inspectInfo, _, inspectErr = dockerClient.ImageInspectWithRaw(context.Background(), imageID)
if client.IsErrNotFound(inspectErr) {
inspectErr = nil
res, pullErr := dockerClient.ImagePull(context.Background(), imageID, types.ImagePullOptions{})
Expand All @@ -97,7 +103,7 @@ func tryPullImage(imageID string) error {
}

if pullErr != nil {
return pullErr
return inspectInfo, pullErr
}

dec := json.NewDecoder(res)
Expand All @@ -111,8 +117,9 @@ func tryPullImage(imageID string) error {
}
// if the final stream object contained an error, return it
if errMsg, ok := m["error"]; ok {
return fmt.Errorf("%v", errMsg)
return inspectInfo, fmt.Errorf("%v", errMsg)
}
inspectInfo, _, inspectErr = dockerClient.ImageInspectWithRaw(context.Background(), imageID)
}
return inspectErr
return inspectInfo, inspectErr
}
12 changes: 9 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
func main() {

config.Init()
config.SetVersion("1.3.5")
config.SetVersion("1.3.7")

controllers.Init()
var conf = config.GetConfig()
Expand All @@ -38,15 +38,21 @@ func main() {
beego.SetLogFuncCall(true)
beego.SetLevel(conf.LogLevel)

ipAddr, bindPort, err := config.GetNodeHTTPAddrIPPort()
if err != nil {
beego.Error("agent httpaddr error:" + err.Error())
}

beego.BConfig.Listen.HTTPPort = bindPort
if conf.DockerClusterEnabled {
clusterOptions := types.NewNodeRegisterOptions(beego.BConfig.Listen.HTTPPort, &conf)
clusterOptions := types.NewNodeRegisterOptions(ipAddr, bindPort, &conf)
if err := types.NodeRegister(clusterOptions); err != nil {
beego.Error("cluster node register error:" + err.Error())
return
}
}
go signalListen()

go signalListen()
beego.Run()
}

Expand Down

0 comments on commit 8404cfb

Please sign in to comment.