Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improvement(k8s): cluster cleanup command now also cleans build sync dir #962

Merged
merged 1 commit into from
Jul 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ import * as Bluebird from "bluebird"
import { CLUSTER_REGISTRY_DEPLOYMENT_NAME } from "../constants"
import { systemNamespace } from "../system"
import { PluginError } from "../../../exceptions"
import { apply } from "../kubectl"
import { apply, kubectl } from "../kubectl"
import { waitForResources } from "../status/status"
import { execInDeployment } from "../container/run"
import { dedent } from "../../../util/string"
import { execInBuilder, getBuilderPodName } from "../container/build"
import { execInBuilder, getBuilderPodName, BuilderExecParams, buildSyncDeploymentName } from "../container/build"
import { getPods } from "../util"

const workspaceSyncDirTtl = 0.5 * 86400 // 2 days

export const cleanupClusterRegistry: PluginCommand = {
name: "cleanup-cluster-registry",
Expand All @@ -42,9 +45,11 @@ export const cleanupClusterRegistry: PluginCommand = {
})
}

const api = await KubeApi.factory(log, provider.config.context)
// Clean old directories from build sync volume
await cleanupBuildSyncVolume(provider, log)

// Scan through all Pods in cluster
const api = await KubeApi.factory(log, provider.config.context)
const imagesInUse = await getImagesInUse(api, provider, log)

// Get images in registry
Expand Down Expand Up @@ -298,3 +303,65 @@ async function deleteImagesFromDaemon(provider: KubernetesProvider, log: LogEntr

log.setSuccess()
}

async function cleanupBuildSyncVolume(provider: KubernetesProvider, log: LogEntry) {
log = log.info({
msg: chalk.white(`Cleaning up old workspaces from build sync volume...`),
status: "active",
})

const podName = await getBuildSyncPodName(provider, log)
const statArgs = ["sh", "-c", 'stat /data/* -c "%n %X"']
const stat = await execInBuildSync({ provider, log, args: statArgs, timeout: 30, podName })

// Filter to directories last accessed more than workspaceSyncDirTtl ago
const minTimestamp = new Date().getTime() / 1000 - workspaceSyncDirTtl

const dirsToDelete = stat.stdout.split("\n")
.filter(Boolean)
.map(line => {
const [dirname, lastAccessed] = line.trim().split(" ")
return { dirname, lastAccessed: parseInt(lastAccessed, 10) }
})
.filter(({ lastAccessed }) => lastAccessed < minTimestamp)

// Delete the director
log.info(`Deleting ${dirsToDelete.length} workspace directories.`)
const deleteArgs = ["rm", "-rf", ...dirsToDelete.map(d => d.dirname)]
await execInBuildSync({ provider, log, args: deleteArgs, timeout: 30, podName })

log.setSuccess()
}

// Returns the name for one of the build-sync pods in the cluster
// (doesn't matter which one, they all use the same volume)
async function getBuildSyncPodName(provider: KubernetesProvider, log: LogEntry) {
Copy link
Collaborator

@eysi09 eysi09 Jul 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment saying that this returns the name of the first build-sync pod found and that there are usually some replicas.

const api = await KubeApi.factory(log, provider.config.context)

const builderStatusRes = await api.apps.readNamespacedDeployment(buildSyncDeploymentName, systemNamespace)
const builderPods = await getPods(api, systemNamespace, builderStatusRes.spec.selector.matchLabels)
const pod = builderPods[0]

if (!pod) {
throw new PluginError(`Could not find running image builder`, {
builderDeploymentName: buildSyncDeploymentName,
systemNamespace,
})
}

return builderPods[0].metadata.name
}

async function execInBuildSync({ provider, log, args, timeout, podName }: BuilderExecParams) {
const execCmd = ["exec", "-i", podName, "--", ...args]

log.verbose(`Running: kubectl ${execCmd.join(" ")}`)

return kubectl.exec({
args: execCmd,
context: provider.config.context,
log,
namespace: systemNamespace,
timeout,
})
}
6 changes: 3 additions & 3 deletions garden-service/src/plugins/kubernetes/container/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const buildTimeout = 600
const kanikoImage = "gcr.io/kaniko-project/executor:v0.8.0"
const registryPort = 5000
const syncDataVolumeName = "garden-build-sync"
const syncDeploymentName = "garden-build-sync"
export const buildSyncDeploymentName = "garden-build-sync"

export async function k8sGetContainerBuildStatus(
params: GetBuildStatusParams<ContainerModule>,
Expand Down Expand Up @@ -130,7 +130,7 @@ const remoteBuild: BuildHandler = async (params) => {
ctx,
log,
namespace: systemNamespace,
targetDeployment: `Deployment/${syncDeploymentName}`,
targetDeployment: `Deployment/${buildSyncDeploymentName}`,
port: RSYNC_PORT,
})

Expand Down Expand Up @@ -215,7 +215,7 @@ const remoteBuild: BuildHandler = async (params) => {
}
}

interface BuilderExecParams {
export interface BuilderExecParams {
provider: KubernetesProvider,
log: LogEntry,
args: string[],
Expand Down