Skip to content
Permalink
Browse files

Check for idle containers [WIP]

  • Loading branch information
erikhofer committed May 2, 2019
1 parent a6cd9ee commit 1a2b52a0937eb5c75f3ff4bdd3de57a2865edd7f
@@ -0,0 +1,3 @@
* text=auto

*.sh text eol=lf
@@ -38,4 +38,12 @@ Vagrant.configure("2") do |config|
&& systemctl restart docker.service
eol
end

# Build IDE container image
config.vm.provision "shell",
inline: "docker build -t cfreak/theia:latest /vagrant/theia"

config.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
end
end
@@ -3,9 +3,11 @@ package de.code_freak.codefreak
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.ComponentScan
import org.springframework.scheduling.annotation.EnableScheduling

@SpringBootApplication
@ComponentScan("de.code_freak.codefreak", "asset.pipeline.springboot")
@EnableScheduling
class CodeFreakApplication

fun main(args: Array<String>) {
@@ -4,12 +4,12 @@ import com.spotify.docker.client.DockerClient
import com.spotify.docker.client.messages.ContainerConfig
import com.spotify.docker.client.messages.HostConfig
import de.code_freak.codefreak.entity.Answer
import de.code_freak.codefreak.repository.AnswerRepository
import org.apache.commons.io.IOUtils
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.context.event.EventListener
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Service
import java.lang.IllegalArgumentException
import java.util.UUID
@@ -27,17 +27,22 @@ class ContainerService(
)
private const val LABEL_PREFIX = "de.code-freak."
const val LABEL_ANSWER_ID = LABEL_PREFIX + "answer-id"
const val SHUTDOWN_TASK_RATE = 1000L * 30
const val SHUTDOWN_IDLE_THRESHOLD = 1000L * 60 * 2
}

private val log = LoggerFactory.getLogger(this::class.java)
private var idleContainers: Map<String, Long> = mapOf()

@Value("\${code-freak.traefik.url}")
private lateinit var traefikUrl: String

@Autowired
private lateinit var answerRepository: AnswerRepository

/**
* Pull all required docker images on startup
* Pull all required docker images
*/
@EventListener(ApplicationReadyEvent::class)
fun pullDockerImages() {
log.info("Pulling latest image for: " + DOCKER_IMAGES.joinToString())
DOCKER_IMAGES.parallelStream().forEach {
@@ -144,4 +149,39 @@ class ContainerService(

protected fun isContainerRunning(containerId: String): Boolean =
docker.inspectContainer(containerId).state().running()

@Transactional
@Scheduled(fixedRate = SHUTDOWN_TASK_RATE, initialDelay = SHUTDOWN_TASK_RATE)
protected fun shutdownIdleIdeContainers() {
// docker exec -it foo lsof -a -i4 -i6 -itcp | grep :3000 | grep ESTABLISHED | wc -l
log.info("Checking for idle containers")
// create a new map to not leak memory if containers disappear in another way
val newIdleContainers: MutableMap<String, Long> = mutableMapOf()
docker.listContainers(DockerClient.ListContainersParam.withLabel(LABEL_ANSWER_ID))
.filter { isContainerRunning(it.id()) }
.forEach {
val containerId = it.id()
val connections = exec(containerId, arrayOf("/opt/code-freak/num-active-connections.sh")).trim()
log.info(connections)
if (connections == "0") {
val idleTime = (idleContainers[containerId] ?: 0) + SHUTDOWN_TASK_RATE
log.info("Container $containerId has been idle for $idleTime ms")
if (idleTime >= SHUTDOWN_IDLE_THRESHOLD) {
val answerId = it.labels()!![LABEL_ANSWER_ID]
log.info("Shutting down container $containerId of answer $answerId")
val answer = answerRepository.findById(UUID.fromString(answerId))
if (answer.isPresent) {
saveAnswerFiles(answer.get())
} else {
log.warn("Answer $answerId not found. Files are not saved!")
}
docker.stopContainer(containerId, 5)
docker.removeContainer(containerId)
} else {
newIdleContainers[containerId] = idleTime
}
}
}
idleContainers = newIdleContainers
}
}
@@ -5,7 +5,7 @@ FROM ubuntu:18.04
ENV DEBIAN_FRONTEND noninteractive

#Common deps
RUN apt-get update && apt-get -y install curl xz-utils wget gpg
RUN apt-get update && apt-get -y install curl xz-utils wget gpg lsof

#Install node and yarn
#From: https://github.com/nodejs/docker-node/blob/6b8d86d6ad59e0d1e7a94cec2e909cad137a028f/8/Dockerfile
@@ -154,6 +154,7 @@ RUN apt-get update && apt-get install -y python build-essential
WORKDIR /home/theia
ADD package.json ./
ADD packages packages
ADD scripts /opt/code-freak

RUN chmod g+rw /home && \
mkdir -p /home/project && \
@@ -0,0 +1,3 @@
#! /bin/bash

lsof -a -i4 -i6 -itcp | grep :3000 | grep ESTABLISHED | wc -l

0 comments on commit 1a2b52a

Please sign in to comment.
You can’t perform that action at this time.