feat: able to push image to docker registry
This commit is contained in:
parent
127880cf8d
commit
8ccb0c88db
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Application" ADD COLUMN "dockerRegistryImageName" TEXT;
|
@ -133,6 +133,7 @@ model Application {
|
|||||||
baseBuildImage String?
|
baseBuildImage String?
|
||||||
settings ApplicationSettings?
|
settings ApplicationSettings?
|
||||||
dockerRegistryId String?
|
dockerRegistryId String?
|
||||||
|
dockerRegistryImageName String?
|
||||||
simpleDockerfile String?
|
simpleDockerfile String?
|
||||||
|
|
||||||
persistentStorage ApplicationPersistentStorage[]
|
persistentStorage ApplicationPersistentStorage[]
|
||||||
|
@ -3,8 +3,8 @@ import crypto from 'crypto';
|
|||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
|
|
||||||
import { copyBaseConfigurationFiles, makeLabelForSimpleDockerfile, makeLabelForStandaloneApplication, saveBuildLog, setDefaultConfiguration } from '../lib/buildPacks/common';
|
import { copyBaseConfigurationFiles, makeLabelForSimpleDockerfile, makeLabelForStandaloneApplication, saveBuildLog, saveDockerRegistryCredentials, setDefaultConfiguration } from '../lib/buildPacks/common';
|
||||||
import { createDirectories, decrypt, defaultComposeConfiguration, executeDockerCmd, getDomain, prisma, decryptApplication, isDev } from '../lib/common';
|
import { createDirectories, decrypt, defaultComposeConfiguration, executeDockerCmd, getDomain, prisma, decryptApplication, isDev, pushToRegistry } from '../lib/common';
|
||||||
import * as importers from '../lib/importers';
|
import * as importers from '../lib/importers';
|
||||||
import * as buildpacks from '../lib/buildPacks';
|
import * as buildpacks from '../lib/buildPacks';
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
|
|
||||||
for (const queueBuild of queuedBuilds) {
|
for (const queueBuild of queuedBuilds) {
|
||||||
actions.push(async () => {
|
actions.push(async () => {
|
||||||
let application = await prisma.application.findUnique({ where: { id: queueBuild.applicationId }, include: { destinationDocker: true, gitSource: { include: { githubApp: true, gitlabApp: true } }, persistentStorage: true, secrets: true, settings: true, teams: true } })
|
let application = await prisma.application.findUnique({ where: { id: queueBuild.applicationId }, include: { dockerRegistry: true, destinationDocker: true, gitSource: { include: { githubApp: true, gitlabApp: true } }, persistentStorage: true, secrets: true, settings: true, teams: true } })
|
||||||
|
|
||||||
let { id: buildId, type, gitSourceId, sourceBranch = null, pullmergeRequestId = null, previewApplicationId = null, forceRebuild, sourceRepository = null } = queueBuild
|
let { id: buildId, type, gitSourceId, sourceBranch = null, pullmergeRequestId = null, previewApplicationId = null, forceRebuild, sourceRepository = null } = queueBuild
|
||||||
application = decryptApplication(application)
|
application = decryptApplication(application)
|
||||||
@ -51,7 +51,8 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
port,
|
port,
|
||||||
persistentStorage,
|
persistentStorage,
|
||||||
exposePort,
|
exposePort,
|
||||||
simpleDockerfile
|
simpleDockerfile,
|
||||||
|
dockerRegistry
|
||||||
} = application
|
} = application
|
||||||
const { workdir } = await createDirectories({ repository: applicationId, buildId });
|
const { workdir } = await createDirectories({ repository: applicationId, buildId });
|
||||||
try {
|
try {
|
||||||
@ -109,6 +110,11 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
}
|
}
|
||||||
|
|
||||||
await fs.writeFile(`${workdir}/Dockerfile`, simpleDockerfile);
|
await fs.writeFile(`${workdir}/Dockerfile`, simpleDockerfile);
|
||||||
|
if (dockerRegistry) {
|
||||||
|
const { url, username, password } = dockerRegistry
|
||||||
|
await saveDockerRegistryCredentials({ url, username, password, workdir })
|
||||||
|
}
|
||||||
|
|
||||||
const labels = makeLabelForSimpleDockerfile({
|
const labels = makeLabelForSimpleDockerfile({
|
||||||
applicationId,
|
applicationId,
|
||||||
type,
|
type,
|
||||||
@ -164,7 +170,7 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
}
|
}
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } });
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const foundBuild = await prisma.build.findUnique({ where: { id: buildId } })
|
const foundBuild = await prisma.build.findUnique({ where: { id: buildId } })
|
||||||
@ -179,10 +185,27 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
if (error !== 1) {
|
if (error !== 1) {
|
||||||
await saveBuildLog({ line: error, buildId, applicationId: application.id });
|
await saveBuildLog({ line: error, buildId, applicationId: application.id });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (application.dockerRegistryImageName) {
|
||||||
|
const customTag = application.dockerRegistryImageName.split(':')[1] || buildId;
|
||||||
|
const imageName = application.dockerRegistryImageName.split(':')[0];
|
||||||
|
await saveBuildLog({ line: `Pushing ${imageName}:${customTag} to Docker Registry... It could take a while...`, buildId, applicationId: application.id });
|
||||||
|
await pushToRegistry(application, workdir, buildId, imageName, customTag)
|
||||||
|
await saveBuildLog({ line: "Success 🎉", buildId, applicationId: application.id });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error.stdout) {
|
||||||
|
await saveBuildLog({ line: error.stdout, buildId, applicationId });
|
||||||
|
}
|
||||||
|
if (error.stderr) {
|
||||||
|
await saveBuildLog({ line: error.stderr, buildId, applicationId });
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (!isDev) {
|
if (!isDev) {
|
||||||
await fs.rm(workdir, { recursive: true, force: true });
|
await fs.rm(workdir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -211,6 +234,7 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
baseBuildImage,
|
baseBuildImage,
|
||||||
deploymentType,
|
deploymentType,
|
||||||
gitCommitHash,
|
gitCommitHash,
|
||||||
|
dockerRegistry
|
||||||
} = application
|
} = application
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@ -231,7 +255,7 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
|
|
||||||
let imageId = applicationId;
|
let imageId = applicationId;
|
||||||
let domain = getDomain(fqdn);
|
let domain = getDomain(fqdn);
|
||||||
|
let tag = null
|
||||||
if (pullmergeRequestId) {
|
if (pullmergeRequestId) {
|
||||||
const previewApplications = await prisma.previewApplication.findMany({ where: { applicationId: originalApplicationId, pullmergeRequestId } })
|
const previewApplications = await prisma.previewApplication.findMany({ where: { applicationId: originalApplicationId, pullmergeRequestId } })
|
||||||
if (previewApplications.length > 0) {
|
if (previewApplications.length > 0) {
|
||||||
@ -330,7 +354,7 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
if (!commit) {
|
if (!commit) {
|
||||||
throw new Error('No commit found?');
|
throw new Error('No commit found?');
|
||||||
}
|
}
|
||||||
let tag = commit.slice(0, 7);
|
tag = commit.slice(0, 7);
|
||||||
if (pullmergeRequestId) {
|
if (pullmergeRequestId) {
|
||||||
tag = `${commit.slice(0, 7)}-${pullmergeRequestId}`;
|
tag = `${commit.slice(0, 7)}-${pullmergeRequestId}`;
|
||||||
}
|
}
|
||||||
@ -500,6 +524,9 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
}
|
}
|
||||||
await fs.writeFile(`${workdir}/.env`, envs.join('\n'));
|
await fs.writeFile(`${workdir}/.env`, envs.join('\n'));
|
||||||
|
|
||||||
|
const { url, username, password } = dockerRegistry
|
||||||
|
await saveDockerRegistryCredentials({ url, username, password, workdir })
|
||||||
|
|
||||||
let envFound = false;
|
let envFound = false;
|
||||||
try {
|
try {
|
||||||
envFound = !!(await fs.stat(`${workdir}/.env`));
|
envFound = !!(await fs.stat(`${workdir}/.env`));
|
||||||
@ -553,7 +580,7 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
}
|
}
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } });
|
|
||||||
if (!pullmergeRequestId) await prisma.application.update({
|
if (!pullmergeRequestId) await prisma.application.update({
|
||||||
where: { id: applicationId },
|
where: { id: applicationId },
|
||||||
data: { configHash: currentHash }
|
data: { configHash: currentHash }
|
||||||
@ -573,10 +600,28 @@ import * as buildpacks from '../lib/buildPacks';
|
|||||||
if (error !== 1) {
|
if (error !== 1) {
|
||||||
await saveBuildLog({ line: error, buildId, applicationId: application.id });
|
await saveBuildLog({ line: error, buildId, applicationId: application.id });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (application.dockerRegistryImageName) {
|
||||||
|
const customTag = application.dockerRegistryImageName.split(':')[1] || tag;
|
||||||
|
const imageName = application.dockerRegistryImageName.split(':')[0];
|
||||||
|
await saveBuildLog({ line: `Pushing ${imageName}:${customTag} to Docker Registry... It could take a while...`, buildId, applicationId: application.id });
|
||||||
|
await pushToRegistry(application, workdir, tag, imageName, customTag)
|
||||||
|
await saveBuildLog({ line: "Success 🎉", buildId, applicationId: application.id });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error.stdout) {
|
||||||
|
await saveBuildLog({ line: error.stdout, buildId, applicationId });
|
||||||
|
}
|
||||||
|
if (error.stderr) {
|
||||||
|
await saveBuildLog({ line: error.stderr, buildId, applicationId });
|
||||||
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (!isDev) {
|
if (!isDev) {
|
||||||
await fs.rm(workdir, { recursive: true, force: true });
|
await fs.rm(workdir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -607,13 +607,13 @@ export function checkPnpm(installCommand = null, buildCommand = null, startComma
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function saveDockerRegistryCredentials({ url, username, password, workdir }) {
|
export async function saveDockerRegistryCredentials({ url, username, password, workdir }) {
|
||||||
let decryptedPassword = decrypt(password);
|
|
||||||
const location = `${workdir}/.docker`;
|
|
||||||
|
|
||||||
if (!username || !password) {
|
if (!username || !password) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let decryptedPassword = decrypt(password);
|
||||||
|
const location = `${workdir}/.docker`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.mkdir(`${workdir}/.docker`);
|
await fs.mkdir(`${workdir}/.docker`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -15,7 +15,7 @@ import sshConfig from 'ssh-config';
|
|||||||
import jsonwebtoken from 'jsonwebtoken';
|
import jsonwebtoken from 'jsonwebtoken';
|
||||||
import { checkContainer, removeContainer } from './docker';
|
import { checkContainer, removeContainer } from './docker';
|
||||||
import { day } from './dayjs';
|
import { day } from './dayjs';
|
||||||
import { saveBuildLog } from './buildPacks/common';
|
import { saveBuildLog, saveDockerRegistryCredentials } from './buildPacks/common';
|
||||||
import { scheduler } from './scheduler';
|
import { scheduler } from './scheduler';
|
||||||
|
|
||||||
export const version = '3.12.0';
|
export const version = '3.12.0';
|
||||||
@ -1713,3 +1713,17 @@ export function decryptApplication(application: any) {
|
|||||||
return application;
|
return application;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function pushToRegistry(application: any, workdir: string, tag: string, imageName: string, customTag: string) {
|
||||||
|
const location = `${workdir}/.docker`
|
||||||
|
const tagCommand = `docker tag ${application.id}:${tag} ${imageName}:${customTag}`
|
||||||
|
const pushCommand = `docker --config ${location} push ${imageName}:${customTag}`
|
||||||
|
await executeDockerCmd({
|
||||||
|
dockerId: application.destinationDockerId,
|
||||||
|
command: tagCommand
|
||||||
|
})
|
||||||
|
await executeDockerCmd({
|
||||||
|
dockerId: application.destinationDockerId,
|
||||||
|
command: pushCommand
|
||||||
|
})
|
||||||
|
}
|
@ -335,7 +335,8 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
|||||||
dockerComposeFile,
|
dockerComposeFile,
|
||||||
dockerComposeFileLocation,
|
dockerComposeFileLocation,
|
||||||
dockerComposeConfiguration,
|
dockerComposeConfiguration,
|
||||||
simpleDockerfile
|
simpleDockerfile,
|
||||||
|
dockerRegistryImageName
|
||||||
} = request.body
|
} = request.body
|
||||||
if (port) port = Number(port);
|
if (port) port = Number(port);
|
||||||
if (exposePort) {
|
if (exposePort) {
|
||||||
@ -375,6 +376,7 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
|||||||
dockerComposeFileLocation,
|
dockerComposeFileLocation,
|
||||||
dockerComposeConfiguration,
|
dockerComposeConfiguration,
|
||||||
simpleDockerfile,
|
simpleDockerfile,
|
||||||
|
dockerRegistryImageName,
|
||||||
...defaultConfiguration,
|
...defaultConfiguration,
|
||||||
connectedDatabase: { update: { hostedDatabaseDBName: baseDatabaseBranch } }
|
connectedDatabase: { update: { hostedDatabaseDBName: baseDatabaseBranch } }
|
||||||
}
|
}
|
||||||
@ -398,6 +400,7 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
|||||||
dockerComposeFileLocation,
|
dockerComposeFileLocation,
|
||||||
dockerComposeConfiguration,
|
dockerComposeConfiguration,
|
||||||
simpleDockerfile,
|
simpleDockerfile,
|
||||||
|
dockerRegistryImageName,
|
||||||
...defaultConfiguration
|
...defaultConfiguration
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -26,7 +26,8 @@ export interface SaveApplication extends OnlyId {
|
|||||||
dockerComposeFile: string,
|
dockerComposeFile: string,
|
||||||
dockerComposeFileLocation: string,
|
dockerComposeFileLocation: string,
|
||||||
dockerComposeConfiguration: string,
|
dockerComposeConfiguration: string,
|
||||||
simpleDockerfile: string
|
simpleDockerfile: string,
|
||||||
|
dockerRegistryImageName: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export interface SaveApplicationSettings extends OnlyId {
|
export interface SaveApplicationSettings extends OnlyId {
|
||||||
|
@ -218,7 +218,7 @@
|
|||||||
<li class="menu-title">
|
<li class="menu-title">
|
||||||
<span>Advanced</span>
|
<span>Advanced</span>
|
||||||
</li>
|
</li>
|
||||||
{#if !application.simpleDockerfile}
|
{#if application.gitSourceId}
|
||||||
<li
|
<li
|
||||||
class="rounded"
|
class="rounded"
|
||||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/revert`}
|
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/revert`}
|
||||||
@ -267,7 +267,7 @@
|
|||||||
</svg>Monitoring</a
|
</svg>Monitoring</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
{#if !application.settings.isBot && !application.simpleDockerfile}
|
{#if !application.settings.isBot && application.gitSourceId}
|
||||||
<li
|
<li
|
||||||
class="rounded"
|
class="rounded"
|
||||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/previews`}
|
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/previews`}
|
||||||
|
@ -568,8 +568,6 @@
|
|||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<label for="registry">Docker Registry</label>
|
<label for="registry">Docker Registry</label>
|
||||||
@ -592,6 +590,24 @@
|
|||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{#if application.dockerRegistry?.id && application.gitSourceId}
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<label for="registry"
|
||||||
|
>Push Image to Registry <Explainer
|
||||||
|
explanation="Push the build image to the specific Docker Registry.<br><br>This is useful if you want to use the image in other places. If you don't fill this the image will be only available on the server.<br><br>Tag is optional. If you don't fill it, the tag will be the same as the git commit hash."
|
||||||
|
/></label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
name="dockerRegistryImageName"
|
||||||
|
id="dockerRegistryImageName"
|
||||||
|
readonly={isDisabled}
|
||||||
|
disabled={isDisabled}
|
||||||
|
class="w-full"
|
||||||
|
placeholder="e.g. coollabsio/myimage (tag will be commit sha) or coollabsio/myimage:tag"
|
||||||
|
bind:value={application.dockerRegistryImageName}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if !isSimpleDockerfile}
|
{#if !isSimpleDockerfile}
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<label for="buildPack">{$t('application.build_pack')} </label>
|
<label for="buildPack">{$t('application.build_pack')} </label>
|
||||||
@ -728,13 +744,13 @@
|
|||||||
<div class="title font-bold pb-3 pt-10 border-b border-coolgray-500 mb-6">
|
<div class="title font-bold pb-3 pt-10 border-b border-coolgray-500 mb-6">
|
||||||
Configuration
|
Configuration
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-flow-row gap-2 px-4 pr-5">
|
<div class="grid grid-flow-row gap-2 px-4 pr-5">
|
||||||
<div class="grid grid-cols-2 items-center pt-4">
|
<div class="grid grid-cols-2 items-center pt-4">
|
||||||
<label for="simpleDockerfile">Dockerfile</label>
|
<label for="simpleDockerfile">Dockerfile</label>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<textarea
|
<textarea
|
||||||
rows=10
|
rows="10"
|
||||||
id="simpleDockerfile"
|
id="simpleDockerfile"
|
||||||
name="simpleDockerfile"
|
name="simpleDockerfile"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
|
Loading…
Reference in New Issue
Block a user