#110: Started fix for docker container versions and k8s support

This commit is contained in:
frikky
2020-09-02 16:11:57 +02:00
13 changed files with 145 additions and 155 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o webapp .
FROM alpine:latest as certs FROM alpine:latest as certs
RUN apk --update add ca-certificates RUN apk --update add ca-certificates
from scratch FROM alpine:3.12
COPY --from=builder /app/ /app COPY --from=builder /app/ /app
COPY --from=builder /app_sdk/ /app_sdk COPY --from=builder /app_sdk/ /app_sdk
+6 -5
View File
@@ -1,9 +1,10 @@
#!/bin/bash #!/bin/bash
NAME=app_sdk NAME=app_sdk
VERSION=0.2.0 VERSION=0.6.0
docker rmi frikky/shuffle:$NAME --force docker rmi docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION --force
docker build . -t frikky/shuffle:$NAME -t frikky/$NAME:$VERSION docker build . -t frikky/shuffle:$NAME -t frikky/$NAME:$VERSION -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION
docker push frikky/shuffle:$NAME #docker push frikky/shuffle:$NAME
docker push frikky/$NAME:$VERSION #docker push frikky/$NAME:$VERSION
docker push docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION
+11 -8
View File
@@ -11,11 +11,12 @@ import (
"fmt" "fmt"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
network "github.com/docker/docker/api/types/network"
"github.com/docker/docker/client" "github.com/docker/docker/client"
natting "github.com/docker/go-connections/nat"
"github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5"
network "github.com/docker/docker/api/types/network"
natting "github.com/docker/go-connections/nat"
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
@@ -180,9 +181,10 @@ func buildImageMemory(fs billy.Filesystem, tags []string, dockerfileFolder strin
// Dockerfile is inside the TAR itself. Not local context // Dockerfile is inside the TAR itself. Not local context
// docker build --build-arg http_proxy=http://my.proxy.url // docker build --build-arg http_proxy=http://my.proxy.url
buildOptions := types.ImageBuildOptions{ buildOptions := types.ImageBuildOptions{
Remove: true, Remove: true,
Tags: tags, Tags: tags,
BuildArgs: map[string]*string{}, BuildArgs: map[string]*string{},
NetworkMode: "host",
} }
httpProxy := os.Getenv("HTTP_PROXY") httpProxy := os.Getenv("HTTP_PROXY")
@@ -242,9 +244,10 @@ func buildImage(tags []string, dockerfileFolder string) error {
dockerFileTarReader := bytes.NewReader(buf.Bytes()) dockerFileTarReader := bytes.NewReader(buf.Bytes())
buildOptions := types.ImageBuildOptions{ buildOptions := types.ImageBuildOptions{
Remove: true, Remove: true,
Tags: tags, Tags: tags,
BuildArgs: map[string]*string{}, BuildArgs: map[string]*string{},
NetworkMode: "host",
} }
httpProxy := os.Getenv("HTTP_PROXY") httpProxy := os.Getenv("HTTP_PROXY")
+1 -1
View File
@@ -666,7 +666,7 @@ func handleApiAuthentication(resp http.ResponseWriter, request *http.Request) (U
if len(Userdata.Username) > 0 { if len(Userdata.Username) > 0 {
return Userdata, nil return Userdata, nil
} else { } else {
return Userdata, errors.New(fmt.Sprintf("User is invalid - no username found: %#v", Userdata)) return Userdata, errors.New(fmt.Sprintf("User is invalid - no username found"))
} }
} }
+7 -7
View File
@@ -1,7 +1,7 @@
version: '3' version: '3'
services: services:
frontend: frontend:
build: ./frontend #build: ./frontend
image: frikky/shuffle:frontend image: frikky/shuffle:frontend
container_name: shuffle-frontend container_name: shuffle-frontend
hostname: shuffle-frontend hostname: shuffle-frontend
@@ -16,19 +16,19 @@ services:
depends_on: depends_on:
- backend - backend
backend: backend:
build: ./backend #build: ./backend
image: frikky/shuffle:backend image: frikky/shuffle:backend
container_name: shuffle-backend container_name: shuffle-backend
hostname: ${BACKEND_HOSTNAME} hostname: ${BACKEND_HOSTNAME}
# Here for debugging: # Here for debugging:
ports: ports:
- "${BACKEND_PORT}:5001" - "${BACKEND_PORT}:5001"
networks: networks:
- shuffle - shuffle
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- ${SHUFFLE_APP_HOTLOAD_LOCATION}:/shuffle-apps - ${SHUFFLE_APP_HOTLOAD_LOCATION}:/shuffle-apps
environment: environment:
- DATASTORE_EMULATOR_HOST=shuffle-database:8000 - DATASTORE_EMULATOR_HOST=shuffle-database:8000
- SHUFFLE_APP_HOTLOAD_FOLDER=/shuffle-apps - SHUFFLE_APP_HOTLOAD_FOLDER=/shuffle-apps
- ORG_ID=${ORG_ID} - ORG_ID=${ORG_ID}
@@ -43,13 +43,13 @@ services:
- database - database
orborus: orborus:
#build: ./functions/onprem/orborus #build: ./functions/onprem/orborus
image: frikky/shuffle:orborus image: docker.pkg.github.com/frikky/shuffle/orborus:0.6.0
container_name: shuffle-orborus container_name: shuffle-orborus
hostname: shuffle-orborus hostname: shuffle-orborus
networks: networks:
- shuffle - shuffle
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
environment: environment:
- ORG_ID=${ORG_ID} - ORG_ID=${ORG_ID}
- ENVIRONMENT_NAME=${ENVIRONMENT_NAME} - ENVIRONMENT_NAME=${ENVIRONMENT_NAME}
+4 -3
View File
@@ -2,13 +2,14 @@ from golang as builder
RUN mkdir /app RUN mkdir /app
WORKDIR /app WORKDIR /app
COPY orborus.go /app/orborus.go
RUN go get github.com/docker/docker/api/types github.com/docker/docker/api/types/container github.com/docker/docker/client RUN go get github.com/docker/docker/api/types github.com/docker/docker/api/types/container github.com/docker/docker/client
COPY orborus.go /app/orborus.go
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o orborus . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o orborus .
from scratch FROM alpine:3.12
RUN apk add --no-cache bash
COPY --from=builder /app/ / COPY --from=builder /app/ /
CMD ["./orborus"] CMD ["./orborus"]
+4 -4
View File
@@ -1,10 +1,10 @@
NAME=orborus NAME=orborus
VERSION=0.1.0 VERSION=0.6.0
echo "Running docker build with $NAME:$VERSION" echo "Running docker build with $NAME:$VERSION"
#docker rmi frikky/shuffle:$NAME --force #docker rmi frikky/shuffle:$NAME --force
docker build . -t frikky/shuffle:$NAME -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t frikky/$NAME:$VERSION docker build . -t frikky/shuffle:$NAME -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t frikky/$NAME:$VERSION
docker push frikky/$NAME:$VERSION #docker push frikky/$NAME:$VERSION
docker push frikky/shuffle:$NAME #docker push frikky/shuffle:$NAME
#docker push docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION docker push docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION
+53 -77
View File
@@ -14,31 +14,31 @@ import (
"log" "log"
"net/http" "net/http"
"os" "os"
"os/exec"
"strings" "strings"
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
network "github.com/docker/docker/api/types/network"
dockerclient "github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
//network "github.com/docker/docker/api/types/network" //network "github.com/docker/docker/api/types/network"
//natting "github.com/docker/go-connections/nat" //natting "github.com/docker/go-connections/nat"
) )
var baseUrl = os.Getenv("BASE_URL")
var baseimagename = "frikky/shuffle"
var shuffleNetwork = "" // Filled in init if found
var dockerApiVersion = os.Getenv("DOCKER_API_VERSION")
var environment = os.Getenv("ENVIRONMENT_NAME")
var orgId = os.Getenv("ORG_ID")
// Starts jobs in bulk, so this could be increased // Starts jobs in bulk, so this could be increased
var sleepTime = 3 var sleepTime = 3
// Timeout if somethinc rashes // Timeout if something rashes
//var workerTimeout = 600
var workerTimeout = 300 var workerTimeout = 300
var appSdkVersion = "0.6.0"
var workerVersion = "0.6.0"
var baseimagename = "docker.pkg.github.com/frikky/shuffle"
var orgId = os.Getenv("ORG_ID")
var baseUrl = os.Getenv("BASE_URL")
var environment = os.Getenv("ENVIRONMENT_NAME")
var dockerApiVersion = os.Getenv("DOCKER_API_VERSION")
var runningMode = strings.ToLower(os.Getenv("RUNNING_MODE"))
type ExecutionRequestWrapper struct { type ExecutionRequestWrapper struct {
Data []ExecutionRequest `json:"data"` Data []ExecutionRequest `json:"data"`
@@ -54,6 +54,7 @@ type ExecutionRequest struct {
} }
var dockercli *dockerclient.Client var dockercli *dockerclient.Client
var containerId string
func init() { func init() {
var err error var err error
@@ -63,48 +64,40 @@ func init() {
panic(fmt.Sprintf("Unable to create docker client: %s", err)) panic(fmt.Sprintf("Unable to create docker client: %s", err))
} }
// FIXME: Move this to global variables? getThisContainerId()
containerIdentifier := "orborus" }
networkIdentifier := "shuffle"
ctx := context.Background() // form id of current running container
containers, err := dockercli.ContainerList(ctx, types.ContainerListOptions{ func getThisContainerId() {
All: true, fCol := ""
})
if err != nil { // some adjusting based on current running mode
log.Printf("Failed getting containers during init - running without network check: %s", err) switch runningMode {
case "kubernetes":
// cgroup will be like:
// 11:net_cls,net_prio:/kubepods/besteffort/podf132b44d-cfcf-43f7-9906-79f58e268333/851466f8b5ed5aa0f265b1c95c6d2bafbc51a38dd5c5a1621b6e586572150009
fCol = "5"
log.Printf("[INFO] Running containerized in Kubernetes!")
case "docker":
// cgroup will be like:
// 12:perf_event:/docker/0f06810364f52a2cd6e80bfba27419cb8a29758a204cd676388f4913bb366f2b
fCol = "3"
log.Printf("[INFO] Running containerized in Docker!")
default:
fCol = "3" // for backward-compatibility with production
log.Printf("[WARNING] RUNNING_MODE not set, so I can't figure out the current container ID! Defaulting to Docker (not Kubernetes).")
} }
// Skip random containers. Only handle things related to Shuffle. if fCol != "" {
for _, container := range containers { cmd := fmt.Sprintf("cat /proc/self/cgroup | grep memory | tail -1 | cut -d/ -f%s", fCol)
found := false out, err := exec.Command("bash", "-c", cmd).Output()
if err == nil {
// Bad states - it might just be created sometimes, leading to now netowkr containerId = strings.TrimSpace(string(out))
//if container.State == "restarting" || container.State == "paused" || container.State == "exited" || container.State == "dead" { } else {
// continue log.Printf("Failed getting container ID: %s", err)
//}
for _, name := range container.Names {
if !strings.Contains(strings.ToLower(name), containerIdentifier) {
found = true
continue
}
} }
if found {
for key, _ := range container.NetworkSettings.Networks {
if strings.Contains(strings.ToLower(key), networkIdentifier) {
shuffleNetwork = key
break
}
}
}
}
if len(shuffleNetwork) > 0 {
log.Printf("Found shuffle network \"%s\" for container %s", shuffleNetwork, containerIdentifier)
} else {
log.Printf("Running Shuffle without a docker network")
} }
} }
@@ -121,40 +114,24 @@ func deployWorker(image string, identifier string, env []string) {
}, },
} }
// Look for Shuffle network and set it // form container id and use it as network source if it's not empty
networkConfig := &network.NetworkingConfig{} if containerId != "" {
if len(shuffleNetwork) > 0 { log.Printf("[INFO] Found container ID %s", containerId)
log.Printf("Starting worker with network %s", shuffleNetwork) hostConfig.NetworkMode = container.NetworkMode(fmt.Sprintf("container:%s", containerId))
networkConfig = &network.NetworkingConfig{
EndpointsConfig: map[string]*network.EndpointSettings{
shuffleNetwork: {
NetworkID: shuffleNetwork,
},
},
}
env = append(env, fmt.Sprintf("DOCKER_NETWORK=%s", shuffleNetwork))
} else { } else {
log.Printf("Starting worker WITHOUT any specified network: %s", shuffleNetwork) log.Printf("[WARNING] Empty self container id, continue without NetworkMode")
} }
// ROFL: https://docker-py.readthedocs.io/en/1.4.0/volumes/
config := &container.Config{ config := &container.Config{
Image: image, Image: image,
Env: env, Env: env,
} }
//test := &network.EndpointSettings{
// Gateway: "helo",
//}
//NetworkID
//if connect.EndpointConfig.NetworkID != "NetworkID" {
cont, err := dockercli.ContainerCreate( cont, err := dockercli.ContainerCreate(
context.Background(), context.Background(),
config, config,
hostConfig, hostConfig,
networkConfig, nil,
nil, nil,
identifier, identifier,
) )
@@ -224,19 +201,18 @@ func initializeImages() {
ctx := context.Background() ctx := context.Background()
// check whether theyre the same first // check whether theyre the same first
//version := "0.1.0"
// fmt.Sprintf("docker.pkg.github.com/frikky/shuffle/orborus:%s", version),
// fmt.Sprintf("docker.pkg.github.com/frikky/shuffle/worker:%s", version),
images := []string{ images := []string{
fmt.Sprintf("docker.io/%s:app_sdk", baseimagename), // fmt.Sprintf("docker.io/%s:app_sdk", baseimagename),
fmt.Sprintf("docker.io/%s:worker", baseimagename), // fmt.Sprintf("docker.io/%s:worker", baseimagename),
fmt.Sprintf("%s/worker:%s", baseimagename, workerVersion),
fmt.Sprintf("%s/app_sdk:%s", baseimagename, appSdkVersion),
} }
pullOptions := types.ImagePullOptions{} pullOptions := types.ImagePullOptions{}
for _, image := range images { for _, image := range images {
reader, err := dockercli.ImagePull(ctx, image, pullOptions) reader, err := dockercli.ImagePull(ctx, image, pullOptions)
if err != nil { if err != nil {
log.Printf("Failed getting %s: %s", image, err) log.Printf("Failed getting image %s: %s", image, err)
continue continue
} }
+1
View File
@@ -3,6 +3,7 @@ docker run \
--env ENVIRONMENT_NAME="Shuffle" \ --env ENVIRONMENT_NAME="Shuffle" \
--env BASE_URL=http://shuffle-backend:5001 \ --env BASE_URL=http://shuffle-backend:5001 \
--env DOCKER_API_VERSION=1.42 \ --env DOCKER_API_VERSION=1.42 \
--env RUNNING_MODE="Docker" \
--network "shuffle_shuffle" \ --network "shuffle_shuffle" \
-v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker.sock:/var/run/docker.sock \
frikky/shuffle:orborus frikky/shuffle:orborus
+14 -19
View File
@@ -1,21 +1,16 @@
#from golang as builder from golang as builder
#
#RUN mkdir /app
#WORKDIR /app
#COPY worker.go /app/worker.go
#
#RUN go get github.com/docker/docker/api/types
#RUN go get github.com/docker/docker/api/types/container
#RUN go get -u github.com/docker/docker/client
#
#RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker .
#
# THis is a workaround until I get docker/docker to build in a dockerfile WORKDIR /app
# PS: This is tricky to google.
# Might not work on some machines.
from scratch
#COPY --from=builder /app/ /
COPY worker.bin /worker.bin
CMD ["./worker.bin"] RUN go get -u github.com/docker/docker/api/types
RUN go get -u github.com/docker/docker/api/types/container
RUN go get -u github.com/docker/docker/client
COPY worker.go /app/worker.go
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker .
FROM alpine:3.12
RUN apk add --no-cache bash
COPY --from=builder /app/ /
CMD ["./worker"]
+4 -4
View File
@@ -1,11 +1,11 @@
NAME=worker NAME=worker
VERSION=0.1.0 VERSION=0.6.0
echo "Running docker build with $NAME:$VERSION" echo "Running docker build with $NAME:$VERSION"
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker.bin . CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker.bin .
docker build . -t frikky/shuffle:$NAME -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t frikky/$NAME:$VERSION docker build . -t frikky/shuffle:$NAME -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t frikky/$NAME:$VERSION
# Push both for now.. # Push both for now..
docker push frikky/$NAME:$VERSION #docker push frikky/$NAME:$VERSION
docker push frikky/shuffle:$NAME #docker push frikky/shuffle:$NAME
#docker push docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION docker push docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION
+35 -23
View File
@@ -11,12 +11,12 @@ import (
"log" "log"
"net/http" "net/http"
"os" "os"
"os/exec"
"strings" "strings"
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
network "github.com/docker/docker/api/types/network"
dockerclient "github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
) )
@@ -25,6 +25,29 @@ var baseUrl = os.Getenv("BASE_URL")
var baseimagename = "frikky/shuffle" var baseimagename = "frikky/shuffle"
var sleepTime = 2 var sleepTime = 2
var containerId string
// form container id of current running container
func getThisContainerId() string {
id := ""
cmd := fmt.Sprintf("cat /proc/self/cgroup | grep memory | tail -1 | cut -d/ -f3")
out, err := exec.Command("bash", "-c", cmd).Output()
if err == nil {
id = strings.TrimSpace(string(out))
}
return id
}
func init() {
containerId = getThisContainerId()
if len(containerId) == 0 {
log.Printf("[ERROR] No container ID found.")
} else {
log.Printf("Found container ID: %s", containerId)
}
}
type User struct { type User struct {
Username string `datastore:"Username" json:"username"` Username string `datastore:"Username" json:"username"`
Password string `datastore:"password,noindex" password:"password,omitempty"` Password string `datastore:"password,noindex" password:"password,omitempty"`
@@ -380,11 +403,11 @@ func shutdown(executionId, workflowId string) {
authorization := os.Getenv("AUTHORIZATION") authorization := os.Getenv("AUTHORIZATION")
if len(authorization) > 0 { if len(authorization) > 0 {
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", authorization)) req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", authorization))
} else {
log.Printf("No authorization specified for abort")
} }
req.Header.Add("Content-Type", "application/json") req.Header.Add("Content-Type", "application/json")
//req.Header.Add("Authorization", authorization)
client := &http.Client{ client := &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
Proxy: nil, Proxy: nil,
@@ -414,6 +437,7 @@ func shutdown(executionId, workflowId string) {
// Deploys the internal worker whenever something happens // Deploys the internal worker whenever something happens
func deployApp(cli *dockerclient.Client, image string, identifier string, env []string) error { func deployApp(cli *dockerclient.Client, image string, identifier string, env []string) error {
// form basic hostConfig
hostConfig := &container.HostConfig{ hostConfig := &container.HostConfig{
LogConfig: container.LogConfig{ LogConfig: container.LogConfig{
Type: "json-file", Type: "json-file",
@@ -421,28 +445,23 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
}, },
} }
// form container id and use it as network source if it's not empty
if containerId != "" {
hostConfig.NetworkMode = container.NetworkMode(fmt.Sprintf("container:%s", containerId))
} else {
log.Printf("[WARNING] Empty self container id, continue without NetworkMode")
}
config := &container.Config{ config := &container.Config{
Image: image, Image: image,
Env: env, Env: env,
} }
networkConfig := &network.NetworkingConfig{}
shuffleNetwork := os.Getenv("DOCKER_NETWORK")
if len(shuffleNetwork) > 0 {
networkConfig = &network.NetworkingConfig{
EndpointsConfig: map[string]*network.EndpointSettings{
shuffleNetwork: {
NetworkID: shuffleNetwork,
},
},
}
}
cont, err := cli.ContainerCreate( cont, err := cli.ContainerCreate(
context.Background(), context.Background(),
config, config,
hostConfig, hostConfig,
networkConfig, nil,
nil, nil,
identifier, identifier,
) )
@@ -1107,13 +1126,6 @@ func main() {
} }
} }
shuffleNetwork := os.Getenv("DOCKER_NETWORK")
if len(shuffleNetwork) > 0 {
log.Printf("Running with Docker network %s", shuffleNetwork)
} else {
log.Printf("No docker network specified for Worker.")
}
// WORKER_TESTING_WORKFLOW should be a workflow ID // WORKER_TESTING_WORKFLOW should be a workflow ID
authorization := "" authorization := ""
executionId := "" executionId := ""
+4 -3
View File
@@ -101,15 +101,15 @@ func getRunner(classname string) string {
return fmt.Sprintf(` return fmt.Sprintf(`
# Run the actual thing after we've checked params # Run the actual thing after we've checked params
def run(request): def run(request):
action = request.get_json() action = request.get_json()
print(action) print(action)
print(type(action)) print(type(action))
authorization_key = action.get("authorization") authorization_key = action.get("authorization")
current_execution_id = action.get("execution_id") current_execution_id = action.get("execution_id")
if action and "name" in action and "app_name" in action: if action and "name" in action and "app_name" in action:
asyncio.run(%s.run(action), debug=True) asyncio.run(%s.run(action), debug=True)
return f'Attempting to execute function {action["name"]} in app {action["app_name"]}' return f'Attempting to execute function {action["name"]} in app {action["app_name"]}'
else: else:
return f'Invalid action' return f'Invalid action'
@@ -610,6 +610,7 @@ func buildImage(client *client.Client, tags []string, dockerBuildCtxDir string)
PullParent: true, PullParent: true,
Remove: true, Remove: true,
Tags: tags, Tags: tags,
NetworkMode: "host",
}, },
) )