Skip to content

Commit

Permalink
(fix) Утечка памяти из-за открытых сокетов
Browse files Browse the repository at this point in the history
* Проблема с утечкой памяти в библиотеке для работы с docker-registry:
    * Создан PR в heroku/docker-registry-client: heroku/docker-registry-client#50
    * В antiopa на данный момент используется форк flant/docker-registry-client ветка master
* Из форка flant/docker-registry-client убрано добавление параметра TLSNextProto для http-транспорта и перенесено непосредственно в antiopa при инициализации docker-registry-client.
* Рефакторинг файлов docker_registry.go и registry_manager.go
    * DockerRegistryInfo перенесен в registry_manager.go
* Клиент DockerRegistry создается один раз на все время работы программы.
* Информация из имени docker-image извлекается один раз на все время работы программы, т.к. имя образа не меняется.
  • Loading branch information
distorhead committed Mar 13, 2018
1 parent 664fb81 commit 4a7c2be
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 49 deletions.
71 changes: 26 additions & 45 deletions docker_registry.go
Original file line number Diff line number Diff line change
@@ -1,60 +1,26 @@
package main

import (
"crypto/tls"
"net"
"net/http"
"strings"
"time"

"github.com/docker/distribution/reference"
registryclient "github.com/flant/docker-registry-client/registry"
"github.com/romana/rlog"
"net/http"
"strings"
)

// TODO данные для доступа к registry серверам нужно хранить в secret-ах.
// TODO по imageInfo.Registry брать данные и подключаться к нужному registry.
// Пока известно, что будет только registry.gitlab.company.com

var DockerRegistryInfo = map[string]map[string]string{
"registry.gitlab.company.com": map[string]string{
"url": "https://registry.gitlab.company.com",
"user": "oauth2",
"password": "qweqwe",
},
// minikube specific
"localhost:5000": map[string]string{
"url": "http://kube-registry.kube-system.svc.cluster.local:5000",
},
}

//const DockerRegistryUrl = "https://registry.gitlab.company.com"
//const DockerRegistryUser = "oauth2"
//const DockerRegistryToken = ""

type DockerImageInfo struct {
Registry string
Repository string
Tag string
}

func DockerRegistryGetImageId(image string) (string, error) {
imageInfo, err := DockerParseImageName(image)
if err != nil {
rlog.Errorf("REGISTRY Problem parsing image %s: %v", image, err)
return "", err
}

url := ""
user := ""
password := ""
if info, has_info := DockerRegistryInfo[imageInfo.Registry]; has_info {
url = info["url"]
user = info["user"]
password = info["password"]
}

// Установить соединение с registry
registry := NewDockerRegistry(url, user, password)

func DockerRegistryGetImageId(imageInfo DockerImageInfo, dockerRegistry *registryclient.Registry) (string, error) {
// Получить описание образа
antiopaManifest, err := registry.ManifestV2(imageInfo.Repository, imageInfo.Tag)
antiopaManifest, err := dockerRegistry.ManifestV2(imageInfo.Repository, imageInfo.Tag)
if err != nil {
rlog.Errorf("REGISTRY cannot get manifest for %s:%s: %v", imageInfo.Repository, imageInfo.Tag, err)
return "", err
Expand Down Expand Up @@ -101,13 +67,28 @@ func RegistryClientLogCallback(format string, args ...interface{}) {
// Этот конструктор не запускает registry.Ping и логирует события через rlog.
func NewDockerRegistry(registryUrl, username, password string) *registryclient.Registry {
url := strings.TrimSuffix(registryUrl, "/")
transport := http.DefaultTransport
transport = registryclient.WrapTransport(transport, url, username, password)

transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 1,
MaxIdleConnsPerHost: 1,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSNextProto: make(map[string]func(string, *tls.Conn) http.RoundTripper),
}

wrappedTransport := registryclient.WrapTransport(transport, url, username, password)

return &registryclient.Registry{
URL: url,
Client: &http.Client{
Transport: transport,
Transport: wrappedTransport,
},
Logf: RegistryClientLogCallback,
}
Expand Down
7 changes: 6 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,12 @@ func Init() {
}

InitKubeNodeManager()
InitRegistryManager()

err = InitRegistryManager()
if err != nil {
rlog.Errorf("Cannot initialize registry manager: %s", err)
os.Exit(1)
}
}

func Run() {
Expand Down
53 changes: 50 additions & 3 deletions registry_manager.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package main

import (
"fmt"
"os"
"time"

registryclient "github.com/flant/docker-registry-client/registry"
"github.com/romana/rlog"
)

Expand All @@ -13,18 +15,62 @@ var (
ImageUpdated chan string
AntiopaImageId string
AntiopaImageName string
AntiopaImageInfo DockerImageInfo
PodName string

DockerRegistry *registryclient.Registry
)

// TODO данные для доступа к registry серверам нужно хранить в secret-ах.
// TODO по imageInfo.Registry брать данные и подключаться к нужному registry.
// Пока известно, что будет только registry.gitlab.company.com
var DockerRegistryInfo = map[string]map[string]string{
"registry.gitlab.company.com": map[string]string{
"url": "https://registry.gitlab.company.com",
"user": "oauth2",
"password": "qweqwe",
},
// minikube specific
"localhost:5000": map[string]string{
"url": "http://kube-registry.kube-system.svc.cluster.local:5000",
},
}

// InitRegistryManager получает имя образа по имени пода и запрашивает id этого образа.
func InitRegistryManager() {
func InitRegistryManager() error {
rlog.Debug("Init registry manager")

// TODO Пока для доступа к registry.gitlab.company.com передаётся временный токен через переменную среды
GitlabToken := os.Getenv("GITLAB_TOKEN")
DockerRegistryInfo["registry.gitlab.company.com"]["password"] = GitlabToken

ImageUpdated = make(chan string)
AntiopaImageName = KubeGetPodImageName(Hostname)
AntiopaImageId, _ = DockerRegistryGetImageId(AntiopaImageName)

var err error
AntiopaImageInfo, err = DockerParseImageName(AntiopaImageName)
if err != nil {
return fmt.Errorf("problem parsing image %s: %v", AntiopaImageName, err)
}

url := ""
user := ""
password := ""
if info, hasInfo := DockerRegistryInfo[AntiopaImageInfo.Registry]; hasInfo {
url = info["url"]
user = info["user"]
password = info["password"]
}
// Создать клиента для подключения к docker-registry
// в единственном экземляре
DockerRegistry = NewDockerRegistry(url, user, password)

AntiopaImageId, err = DockerRegistryGetImageId(AntiopaImageInfo, DockerRegistry)
if err != nil {
return err
}

return nil
}

// RunRegistryManager каждые 10 секунд проверяет
Expand All @@ -38,7 +84,8 @@ func RunRegistryManager() {
select {
case <-ticker.C:
rlog.Debugf("Checking registry for updates")
imageID, err := DockerRegistryGetImageId(AntiopaImageName)

imageID, err := DockerRegistryGetImageId(AntiopaImageInfo, DockerRegistry)
if err != nil {
rlog.Errorf("REGISTRY Cannot check image id: %v", err)
} else {
Expand Down

0 comments on commit 4a7c2be

Please sign in to comment.