diff --git a/apps/api/prisma/migrations/20221129101300_keep_docker_images_locally_setting/migration.sql b/apps/api/prisma/migrations/20221129101300_keep_docker_images_locally_setting/migration.sql new file mode 100644 index 000000000..780b66051 --- /dev/null +++ b/apps/api/prisma/migrations/20221129101300_keep_docker_images_locally_setting/migration.sql @@ -0,0 +1,35 @@ +-- AlterTable +ALTER TABLE "Application" ADD COLUMN "gitCommitHash" TEXT; + +-- RedefineTables +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Setting" ( + "id" TEXT NOT NULL PRIMARY KEY, + "fqdn" TEXT, + "dualCerts" BOOLEAN NOT NULL DEFAULT false, + "minPort" INTEGER NOT NULL DEFAULT 9000, + "maxPort" INTEGER NOT NULL DEFAULT 9100, + "DNSServers" TEXT NOT NULL DEFAULT '1.1.1.1,8.8.8.8', + "ipv4" TEXT, + "ipv6" TEXT, + "arch" TEXT, + "concurrentBuilds" INTEGER NOT NULL DEFAULT 1, + "applicationStoragePathMigrationFinished" BOOLEAN NOT NULL DEFAULT false, + "numberOfDockerImagesKeptLocally" INTEGER NOT NULL DEFAULT 3, + "proxyDefaultRedirect" TEXT, + "doNotTrack" BOOLEAN NOT NULL DEFAULT false, + "sentryDSN" TEXT, + "isAPIDebuggingEnabled" BOOLEAN NOT NULL DEFAULT false, + "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT true, + "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false, + "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true, + "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL +); +INSERT INTO "new_Setting" ("DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "doNotTrack", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "sentryDSN", "updatedAt") SELECT "DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "doNotTrack", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "sentryDSN", "updatedAt" FROM "Setting"; +DROP TABLE "Setting"; +ALTER TABLE "new_Setting" RENAME TO "Setting"; +CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn"); +PRAGMA foreign_key_check; +PRAGMA foreign_keys=ON; diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index 9d5485deb..3deb42c60 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -30,6 +30,7 @@ model Setting { arch String? concurrentBuilds Int @default(1) applicationStoragePathMigrationFinished Boolean @default(false) + numberOfDockerImagesKeptLocally Int @default(3) proxyDefaultRedirect String? doNotTrack Boolean @default(false) sentryDSN String? diff --git a/apps/api/src/jobs/deployApplication.ts b/apps/api/src/jobs/deployApplication.ts index 09e92543a..2416e43c6 100644 --- a/apps/api/src/jobs/deployApplication.ts +++ b/apps/api/src/jobs/deployApplication.ts @@ -65,6 +65,7 @@ import * as buildpacks from '../lib/buildPacks'; baseImage, baseBuildImage, deploymentType, + gitCommitHash, } = application let { @@ -169,7 +170,7 @@ import * as buildpacks from '../lib/buildPacks'; githubAppId: gitSource.githubApp?.id, gitlabAppId: gitSource.gitlabApp?.id, customPort: gitSource.customPort, - gitCommitHash: gitCommitHash, + gitCommitHash, configuration, repository, branch, diff --git a/apps/api/src/lib/buildPacks/common.ts b/apps/api/src/lib/buildPacks/common.ts index c8c383564..aca4af9fa 100644 --- a/apps/api/src/lib/buildPacks/common.ts +++ b/apps/api/src/lib/buildPacks/common.ts @@ -635,7 +635,6 @@ export async function buildImage({ const cache = `${applicationId}:${tag}${isCache ? '-cache' : ''}` const { dockerRegistry: { url, username, password } } = await prisma.application.findUnique({ where: { id: applicationId }, select: { dockerRegistry: true } }) const location = await saveDockerRegistryCredentials({ url, username, password, workdir }) - console.log(`docker ${location ? `--config ${location}` : ''} build --progress plain -f ${workdir}/${dockerFile} -t ${cache} --build-arg SOURCE_COMMIT=${commit} ${workdir}`) await executeDockerCmd({ debug, buildId, applicationId, dockerId, command: `docker ${location ? `--config ${location}` : ''} build --progress plain -f ${workdir}/${dockerFile} -t ${cache} --build-arg SOURCE_COMMIT=${commit} ${workdir}` }) diff --git a/apps/api/src/lib/common.ts b/apps/api/src/lib/common.ts index 18153b8b3..40fd6163f 100644 --- a/apps/api/src/lib/common.ts +++ b/apps/api/src/lib/common.ts @@ -1587,22 +1587,44 @@ export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) { } } catch (error) { } if (lowDiskSpace || force) { - // if (isDev) { - // if (!force) console.log(`[DEV MODE] Low disk space: ${lowDiskSpace}`); - // return; - // } + // Cleanup images that are not used + try { + await executeDockerCmd({ dockerId, command: `docker image prune -f` }); + } catch (error) { } + + const { numberOfDockerImagesKeptLocally } = await prisma.setting.findUnique({ where: { id: '0' } }) + const { stdout: images } = await executeDockerCmd({ + dockerId, + command: `docker images | grep -v "" | grep -v REPOSITORY | awk '{print $1, $2}'` + }); + const imagesArray = images.trim().replaceAll(' ', ':').split('\n'); + const imagesSet = new Set(imagesArray.map((image) => image.split(':')[0])); + let deleteImage = [] + for (const image of imagesSet) { + let keepImage = [] + for (const image2 of imagesArray) { + if (image2.startsWith(image)) { + if (keepImage.length >= numberOfDockerImagesKeptLocally) { + deleteImage.push(image2) + } else { + keepImage.push(image2) + } + } + + } + } + for (const image of deleteImage) { + await executeDockerCmd({ dockerId, command: `docker image rm -f ${image}` }); + } + + // Prune coolify managed containers try { await executeDockerCmd({ dockerId, command: `docker container prune -f --filter "label=coolify.managed=true"` }); } catch (error) { } - try { - await executeDockerCmd({ dockerId, command: `docker image prune -f` }); - } catch (error) { } - try { - await executeDockerCmd({ dockerId, command: `docker image prune -a -f` }); - } catch (error) { } + // Cleanup build caches try { await executeDockerCmd({ dockerId, command: `docker builder prune -a -f` }); diff --git a/apps/api/src/routes/api/v1/settings/handlers.ts b/apps/api/src/routes/api/v1/settings/handlers.ts index 3a91449cc..91f2703a1 100644 --- a/apps/api/src/routes/api/v1/settings/handlers.ts +++ b/apps/api/src/routes/api/v1/settings/handlers.ts @@ -53,7 +53,8 @@ export async function listAllSettings(request: FastifyRequest) { } export async function saveSettings(request: FastifyRequest, reply: FastifyReply) { try { - const { + let { + numberOfDockerImagesKeptLocally, doNotTrack, fqdn, isAPIDebuggingEnabled, @@ -67,9 +68,12 @@ export async function saveSettings(request: FastifyRequest, reply: proxyDefaultRedirect } = request.body const { id } = await listSettings(); + if (numberOfDockerImagesKeptLocally) { + numberOfDockerImagesKeptLocally = Number(numberOfDockerImagesKeptLocally) + } await prisma.setting.update({ where: { id }, - data: { doNotTrack, isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled, DNSServers, isAPIDebuggingEnabled, } + data: { numberOfDockerImagesKeptLocally, doNotTrack, isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled, DNSServers, isAPIDebuggingEnabled, } }); if (fqdn) { await prisma.setting.update({ where: { id }, data: { fqdn } }); diff --git a/apps/api/src/routes/api/v1/settings/types.ts b/apps/api/src/routes/api/v1/settings/types.ts index 8e0acc6bc..76212f158 100644 --- a/apps/api/src/routes/api/v1/settings/types.ts +++ b/apps/api/src/routes/api/v1/settings/types.ts @@ -2,6 +2,7 @@ import { OnlyId } from "../../../../types" export interface SaveSettings { Body: { + numberOfDockerImagesKeptLocally: number, doNotTrack: boolean, fqdn: string, isAPIDebuggingEnabled: boolean, diff --git a/apps/ui/src/routes/applications/[id]/index.svelte b/apps/ui/src/routes/applications/[id]/index.svelte index e484f5c98..7a1ecbc64 100644 --- a/apps/ui/src/routes/applications/[id]/index.svelte +++ b/apps/ui/src/routes/applications/[id]/index.svelte @@ -517,20 +517,28 @@
- {#if isDisabled} +
- {:else} - - {/if} + Commits + + +
diff --git a/apps/ui/src/routes/settings/coolify.svelte b/apps/ui/src/routes/settings/coolify.svelte index d5206e952..58e0756dc 100644 --- a/apps/ui/src/routes/settings/coolify.svelte +++ b/apps/ui/src/routes/settings/coolify.svelte @@ -36,6 +36,7 @@ let maxPort = settings.maxPort; let proxyDefaultRedirect = settings.proxyDefaultRedirect; let doNotTrack = settings.doNotTrack; + let numberOfDockerImagesKeptLocally = settings.numberOfDockerImagesKeptLocally; let forceSave = false; let fqdn = settings.fqdn; @@ -165,6 +166,9 @@ if (proxyDefaultRedirect !== settings.proxyDefaultRedirect) { await post(`/settings`, { proxyDefaultRedirect }); } + if (numberOfDockerImagesKeptLocally !== settings.numberOfDockerImagesKeptLocally) { + await post(`/settings`, { numberOfDockerImagesKeptLocally }); + } if (minPort !== settings.minPort || maxPort !== settings.maxPort) { await post(`/settings`, { minPort, maxPort }); settings.minPort = minPort; @@ -393,6 +397,25 @@ on:click|preventDefault|stopPropagation={rollback}>Rollback
+
+
+ Number of Docker Images kept locally + +
+ +
{$t('forms.public_port_range')}