Skip to content

Commit 9fcae85

Browse files
authored
Merge pull request #26 from aojea/docker2
Run CCM inside a container
2 parents e2f6d5f + 6f278e6 commit 9fcae85

4 files changed

Lines changed: 106 additions & 27 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ COPY . .
88
RUN make build
99

1010
# build real cloud-provider-kind image
11-
FROM gcr.io/distroless/static-debian12
11+
FROM docker:25.0-dind
1212
COPY --from=0 --chown=root:root ./go/src/bin/cloud-provider-kind /bin/cloud-provider-kind
1313
ENTRYPOINT ["/bin/cloud-provider-kind"]

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ cd cloud-provider-kind && make
3535
sudo mv ./bin/cloud-provider-kind /usr/local/bin/cloud-provider-kind
3636
```
3737

38+
Another alternative is to run it as a container, but this will require to mount
39+
the docker socket inside the container:
40+
41+
```sh
42+
docker build . -t aojea/cloud-provider-kind:v0.1
43+
# using the host network
44+
docker run --rm --network host -v /var/run/docker.sock:/var/run/docker.sock aojea/cloud-provider-kind:v0.1
45+
# or the kind network
46+
docker run --rm --network kind -v /var/run/docker.sock:/var/run/docker.sock aojea/cloud-provider-kind:v0.1
47+
```
48+
3849
## How to use it
3950

4051
Run a KIND cluster:

pkg/controller/controller.go

Lines changed: 93 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package controller
22

33
import (
44
"context"
5+
"crypto/tls"
6+
"fmt"
7+
"io"
58
"net/http"
69
"time"
710

@@ -47,20 +50,10 @@ func New(logger log.Logger) *Controller {
4750
}
4851

4952
func (c *Controller) Run(ctx context.Context) {
53+
defer cleanup()
5054
for {
5155
select {
5256
case <-ctx.Done():
53-
// cleanup
54-
containers, err := container.ListByLabel(constants.NodeCCMLabelKey)
55-
if err != nil {
56-
klog.Errorf("can't list containers: %v", err)
57-
return
58-
}
59-
for _, id := range containers {
60-
if err := container.Delete(id); err != nil {
61-
klog.Errorf("can't delete container %s: %v", id, err)
62-
}
63-
}
6457
return
6558
default:
6659
}
@@ -72,27 +65,20 @@ func (c *Controller) Run(ctx context.Context) {
7265

7366
// add new ones
7467
for _, cluster := range clusters {
68+
select {
69+
case <-ctx.Done():
70+
return
71+
default:
72+
}
73+
7574
klog.V(3).Infof("processing cluster %s", cluster)
7675
_, ok := c.clusters[cluster]
7776
if ok {
7877
klog.V(3).Infof("cluster %s already exist", cluster)
7978
continue
8079
}
8180

82-
// get kubeconfig
83-
kconfig, err := c.kind.KubeConfig(cluster, false)
84-
if err != nil {
85-
klog.Errorf("Failed to get kubeconfig for cluster %s: %v", cluster, err)
86-
continue
87-
}
88-
89-
config, err := clientcmd.RESTConfigFromKubeConfig([]byte(kconfig))
90-
if err != nil {
91-
klog.Errorf("Failed to convert kubeconfig for cluster %s: %v", cluster, err)
92-
continue
93-
}
94-
95-
kubeClient, err := kubernetes.NewForConfig(config)
81+
kubeClient, err := c.getKubeClient(ctx, cluster)
9682
if err != nil {
9783
klog.Errorf("Failed to create kubeClient for cluster %s: %v", cluster, err)
9884
continue
@@ -122,6 +108,75 @@ func (c *Controller) Run(ctx context.Context) {
122108
}
123109
}
124110

111+
// getKubeClient returns a kubeclient depending if the ccm runs inside a container
112+
// inside the same docker network that the kind cluster or run externally in the host
113+
// It tries first to connect to the external endpoint
114+
func (c *Controller) getKubeClient(ctx context.Context, cluster string) (kubernetes.Interface, error) {
115+
httpClient := &http.Client{
116+
Timeout: 5 * time.Second,
117+
Transport: &http.Transport{
118+
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
119+
},
120+
}
121+
// try internal first
122+
for _, internal := range []bool{false, true} {
123+
kconfig, err := c.kind.KubeConfig(cluster, internal)
124+
if err != nil {
125+
klog.Errorf("Failed to get kubeconfig for cluster %s: %v", cluster, err)
126+
continue
127+
}
128+
129+
config, err := clientcmd.RESTConfigFromKubeConfig([]byte(kconfig))
130+
if err != nil {
131+
klog.Errorf("Failed to convert kubeconfig for cluster %s: %v", cluster, err)
132+
continue
133+
}
134+
135+
// check that the apiserver is reachable before continue
136+
// to fail fast and avoid waiting until the client operations timeout
137+
var ok bool
138+
for i := 0; i < 5; i++ {
139+
select {
140+
case <-ctx.Done():
141+
return nil, ctx.Err()
142+
default:
143+
}
144+
if probeHTTP(httpClient, config.Host) {
145+
ok = true
146+
break
147+
}
148+
time.Sleep(time.Second * time.Duration(i))
149+
}
150+
if !ok {
151+
klog.Errorf("Failed to connect to apiserver %s: %v", cluster, err)
152+
continue
153+
}
154+
155+
kubeClient, err := kubernetes.NewForConfig(config)
156+
if err != nil {
157+
klog.Errorf("Failed to create kubeClient for cluster %s: %v", cluster, err)
158+
continue
159+
}
160+
return kubeClient, err
161+
}
162+
return nil, fmt.Errorf("can not find a working kubernetes clientset")
163+
}
164+
165+
func probeHTTP(client *http.Client, address string) bool {
166+
klog.Infof("probe HTTP address %s", address)
167+
resp, err := client.Get(address)
168+
if err != nil {
169+
klog.Infof("Failed to connect to HTTP address %s: %v", address, err)
170+
return false
171+
}
172+
defer resp.Body.Close()
173+
// drain the body
174+
io.ReadAll(resp.Body) // nolint:errcheck
175+
// we only want to verify connectivity so don't need to check the http status code
176+
// as the apiserver may not be ready
177+
return true
178+
}
179+
125180
// TODO: implement leader election to not have problems with multiple providers
126181
// ref: https://github.com/kubernetes/kubernetes/blob/d97ea0f705847f90740cac3bc3dd8f6a4026d0b5/cmd/kube-scheduler/app/server.go#L211
127182
func startCloudControllerManager(ctx context.Context, clusterName string, kubeClient kubernetes.Interface, cloud cloudprovider.Interface) (*ccm, error) {
@@ -194,3 +249,16 @@ func startCloudControllerManager(ctx context.Context, clusterName string, kubeCl
194249
nodeController: nodeController,
195250
cancelFn: cancel}, nil
196251
}
252+
253+
func cleanup() {
254+
containers, err := container.ListByLabel(constants.NodeCCMLabelKey)
255+
if err != nil {
256+
klog.Errorf("can't list containers: %v", err)
257+
return
258+
}
259+
for _, id := range containers {
260+
if err := container.Delete(id); err != nil {
261+
klog.Errorf("can't delete container %s: %v", id, err)
262+
}
263+
}
264+
}

pkg/loadbalancer/proxy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
)
1818

1919
// proxyImage defines the loadbalancer image:tag
20-
const proxyImage = "kindest/haproxy:v20230330-2f738c2"
20+
const proxyImage = "docker.io/kindest/haproxy:v20230606-42a2262b"
2121

2222
// proxyConfigPath defines the path to the config file in the image
2323
const proxyConfigPath = "/usr/local/etc/haproxy/haproxy.cfg"

0 commit comments

Comments
 (0)