@vaharoni/devops 1.2.18 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-RZ46YYZZ.js → chunk-6FEVIEFY.js} +2 -1
- package/dist/{chunk-WKP7EQNU.js → chunk-QOZ6NZJC.js} +1 -1
- package/dist/{chunk-N7EX3HJH.js → chunk-UZAJJUGJ.js} +1 -1
- package/dist/devops.js +32 -33
- package/dist/index.d.ts +6 -3
- package/dist/index.js +2 -2
- package/dist/plugins.js +2 -2
- package/dist/src/target-templates/infra-variants/digitalocean/.devops/config/constants.yaml +2 -2
- package/dist/src/target-templates/infra-variants/digitalocean/.github/workflows/k8s-build.yaml +13 -13
- package/dist/src/target-templates/infra-variants/gcloud/.devops/config/constants.yaml +2 -2
- package/dist/src/target-templates/infra-variants/gcloud/.github/workflows/k8s-build.yaml +15 -15
- package/dist/src/target-templates/infra-variants/hetzner/.devops/config/constants.yaml +6 -2
- package/dist/src/target-templates/infra-variants/hetzner/.github/workflows/k8s-build.yaml +13 -13
- package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry-with-oidc@v1/action.yaml +29 -0
- package/{src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry@v1 → dist/src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry-with-sa@v1}/action.yaml +2 -2
- package/package.json +1 -1
- package/src/cli/core/constant.ts +1 -1
- package/src/cli/core/init.ts +16 -15
- package/src/cli/core/namespace.ts +5 -5
- package/src/cli/core/registry.ts +1 -1
- package/src/libs/digital-ocean/container-reg.ts +2 -2
- package/src/libs/{hetzner/reg-secret.ts → registry/image-pull-secret.ts} +9 -9
- package/src/target-templates/infra-variants/digitalocean/.devops/config/constants.yaml +2 -2
- package/src/target-templates/infra-variants/digitalocean/.github/workflows/k8s-build.yaml +13 -13
- package/src/target-templates/infra-variants/gcloud/.devops/config/constants.yaml +2 -2
- package/src/target-templates/infra-variants/gcloud/.github/workflows/k8s-build.yaml +15 -15
- package/src/target-templates/infra-variants/hetzner/.devops/config/constants.yaml +6 -2
- package/src/target-templates/infra-variants/hetzner/.github/workflows/k8s-build.yaml +13 -13
- package/src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry-with-oidc@v1/action.yaml +29 -0
- package/{dist/src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry@v1 → src/target-templates/lang-variants-common/typescript/.github/actions/registry/connect-to-artifact-registry-with-sa@v1}/action.yaml +2 -2
- package/src/types/index.ts +2 -1
- /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{build-image@v1 → common/build-image@v1}/action.yaml +0 -0
- /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{db-migrate@v1 → common/db-migrate@v1}/action.yaml +0 -0
- /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{deploy-image-cloudrun@v1 → common/deploy-image-cloudrun@v1}/action.yaml +0 -0
- /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{deploy-image-k8s@v1 → common/deploy-image-k8s@v1}/action.yaml +0 -0
- /package/dist/src/target-templates/lang-variants-common/typescript/.github/actions/{setup-prereq@v1 → common/setup-prereq@v1}/action.yaml +0 -0
- /package/src/target-templates/lang-variants-common/typescript/.github/actions/{build-image@v1 → common/build-image@v1}/action.yaml +0 -0
- /package/src/target-templates/lang-variants-common/typescript/.github/actions/{db-migrate@v1 → common/db-migrate@v1}/action.yaml +0 -0
- /package/src/target-templates/lang-variants-common/typescript/.github/actions/{deploy-image-cloudrun@v1 → common/deploy-image-cloudrun@v1}/action.yaml +0 -0
- /package/src/target-templates/lang-variants-common/typescript/.github/actions/{deploy-image-k8s@v1 → common/deploy-image-k8s@v1}/action.yaml +0 -0
- /package/src/target-templates/lang-variants-common/typescript/.github/actions/{setup-prereq@v1 → common/setup-prereq@v1}/action.yaml +0 -0
|
@@ -9,7 +9,8 @@ import { z } from "zod";
|
|
|
9
9
|
var SUPPORTED_LANGUAGES = ["python", "node"];
|
|
10
10
|
var constFileSchema = z.object({
|
|
11
11
|
"project-name": z.string(),
|
|
12
|
-
"infra": z.enum(["
|
|
12
|
+
"registry-infra": z.enum(["digitalocean", "gcp", "harbor"]),
|
|
13
|
+
"use-image-pull-secret": z.boolean().optional(),
|
|
13
14
|
"image-versions-to-keep": z.number().optional(),
|
|
14
15
|
"registry-base-url": z.string(),
|
|
15
16
|
"registry-image-path-prefix": z.string().optional(),
|
package/dist/devops.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import {
|
|
3
3
|
InternalToken
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UZAJJUGJ.js";
|
|
5
5
|
import {
|
|
6
6
|
CLICommandParser,
|
|
7
7
|
CommandExecutor,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
printUsageAndExit,
|
|
25
25
|
secretName,
|
|
26
26
|
upsertConfigMapCommand
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-QOZ6NZJC.js";
|
|
28
28
|
import {
|
|
29
29
|
IGNORED_PATHS,
|
|
30
30
|
__export,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
getWorkspace,
|
|
37
37
|
globEnvYamlFiles,
|
|
38
38
|
workspaceDirectoryForLanguage
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-6FEVIEFY.js";
|
|
40
40
|
|
|
41
41
|
// src/devops.ts
|
|
42
42
|
import { globSync as globSync2 } from "glob";
|
|
@@ -1103,7 +1103,7 @@ var consoleCommand = { command: "console", oneLiner: oneLiner6, keyExamples: key
|
|
|
1103
1103
|
|
|
1104
1104
|
// src/cli/core/constant.ts
|
|
1105
1105
|
var oneLiner7 = "Prints to stdout a constant from constant.yaml";
|
|
1106
|
-
var keyExamples7 = `$ devops constant infra`;
|
|
1106
|
+
var keyExamples7 = `$ devops constant registry-infra`;
|
|
1107
1107
|
var usage7 = `
|
|
1108
1108
|
${oneLiner7}
|
|
1109
1109
|
|
|
@@ -1741,12 +1741,12 @@ async function createFiles() {
|
|
|
1741
1741
|
}
|
|
1742
1742
|
tc.enableSubtitution(".devops/config/images.yaml");
|
|
1743
1743
|
tc.setMessageGenerator(".envrc", envrcMessage);
|
|
1744
|
-
const gitIgnore = gitIgnoreContent(userChoices.
|
|
1744
|
+
const gitIgnore = gitIgnoreContent(userChoices.infraPreset, userChoices.usePython);
|
|
1745
1745
|
tc.addGeneratedFile(".gitignore", gitIgnore);
|
|
1746
1746
|
tc.setMessageGenerator(".gitignore", gitignoreMessageGen(gitIgnore));
|
|
1747
|
-
tc.addCopiedFolder(`infra-variants/${userChoices.
|
|
1747
|
+
tc.addCopiedFolder(`infra-variants/${userChoices.infraPreset}`, ".");
|
|
1748
1748
|
tc.enableSubtitution(".devops/config/constants.yaml");
|
|
1749
|
-
if (userChoices.
|
|
1749
|
+
if (userChoices.infraPreset === "hetzner") {
|
|
1750
1750
|
tc.enableSubtitution(".devops/infra/hetzner/harbor-cert.yaml");
|
|
1751
1751
|
tc.enableSubtitution(".devops/infra/hetzner/harbor-values.yaml");
|
|
1752
1752
|
tc.enableSubtitution(".devops/infra/hetzner/hcloud-config.yaml");
|
|
@@ -1804,12 +1804,12 @@ function packageJsonMessage(usePrisma) {
|
|
|
1804
1804
|
"applications/**"${prismaMessage}
|
|
1805
1805
|
],`)}`;
|
|
1806
1806
|
}
|
|
1807
|
-
function gitIgnoreContent(
|
|
1807
|
+
function gitIgnoreContent(infraPreset, usePython) {
|
|
1808
1808
|
const common = `**/.env*
|
|
1809
1809
|
config/kubeconfig
|
|
1810
1810
|
tmp/**
|
|
1811
1811
|
!tmp/**/.gitkeep`;
|
|
1812
|
-
const gcloud =
|
|
1812
|
+
const gcloud = infraPreset === "gcloud" ? "config/gke_gcloud_auth_plugin_cache" : null;
|
|
1813
1813
|
const python = usePython ? `venv/
|
|
1814
1814
|
**/__pycache__` : null;
|
|
1815
1815
|
return [common, gcloud, python].filter(Boolean).join("\n");
|
|
@@ -1854,12 +1854,12 @@ function getUserChoices(projectName) {
|
|
|
1854
1854
|
},
|
|
1855
1855
|
{
|
|
1856
1856
|
type: "list",
|
|
1857
|
-
name: "
|
|
1858
|
-
message: "
|
|
1857
|
+
name: "infraPreset",
|
|
1858
|
+
message: "Select your infrastructure preset:",
|
|
1859
1859
|
choices: [
|
|
1860
|
-
{ name: "Google Cloud", value: "gcloud" },
|
|
1861
|
-
{ name: "Digital Ocean", value: "digitalocean" },
|
|
1862
|
-
{ name: "Hetzner", value: "hetzner" }
|
|
1860
|
+
{ name: "Google Cloud (GKE + GCP Registry)", value: "gcloud" },
|
|
1861
|
+
{ name: "Digital Ocean (DO K8s + DO Registry)", value: "digitalocean" },
|
|
1862
|
+
{ name: "Hetzner (Hetzner K8s + Harbor)", value: "hetzner" }
|
|
1863
1863
|
]
|
|
1864
1864
|
},
|
|
1865
1865
|
{
|
|
@@ -1867,21 +1867,21 @@ function getUserChoices(projectName) {
|
|
|
1867
1867
|
name: "gcloudProjectId",
|
|
1868
1868
|
message: "Enter the GCP project ID (default: 'changeme')",
|
|
1869
1869
|
default: "changeme",
|
|
1870
|
-
when: (answers) => answers.
|
|
1870
|
+
when: (answers) => answers.infraPreset === "gcloud"
|
|
1871
1871
|
},
|
|
1872
1872
|
{
|
|
1873
1873
|
type: "input",
|
|
1874
1874
|
name: "registryImagePathPrefix",
|
|
1875
1875
|
message: (answers) => `Enter your Digital Ocean container registry name (default: '${answers.projectName}')`,
|
|
1876
1876
|
default: (answers) => answers.projectName,
|
|
1877
|
-
when: (answers) => answers.
|
|
1877
|
+
when: (answers) => answers.infraPreset === "digitalocean"
|
|
1878
1878
|
},
|
|
1879
1879
|
{
|
|
1880
1880
|
type: "input",
|
|
1881
1881
|
name: "registryBaseUrl",
|
|
1882
1882
|
message: (answers) => `Enter your registry base URL (default: 'registry.${answers.stagingDomain}')`,
|
|
1883
1883
|
default: (answers) => `registry.${answers.stagingDomain}`,
|
|
1884
|
-
when: (answers) => answers.
|
|
1884
|
+
when: (answers) => answers.infraPreset === "hetzner"
|
|
1885
1885
|
},
|
|
1886
1886
|
{
|
|
1887
1887
|
type: "confirm",
|
|
@@ -2067,22 +2067,21 @@ function run11(cmdObj) {
|
|
|
2067
2067
|
}
|
|
2068
2068
|
var job = { oneLiner: oneLiner11, keyExamples: keyExamples11, run: run11 };
|
|
2069
2069
|
|
|
2070
|
-
// src/libs/
|
|
2070
|
+
// src/libs/registry/image-pull-secret.ts
|
|
2071
|
+
var SECRET_NAME = "external-registry-secret";
|
|
2072
|
+
var SOURCE_NAMESPACE = "default";
|
|
2071
2073
|
function isApplicable() {
|
|
2072
|
-
const
|
|
2073
|
-
if (
|
|
2074
|
-
console.warn(
|
|
2075
|
-
"Setting up registry permissions is only needed for Harbor in a Hetzner setup"
|
|
2076
|
-
);
|
|
2074
|
+
const useImagePullSecret = getConst("use-image-pull-secret");
|
|
2075
|
+
if (!useImagePullSecret) {
|
|
2077
2076
|
return false;
|
|
2078
2077
|
}
|
|
2079
2078
|
return true;
|
|
2080
2079
|
}
|
|
2081
|
-
function
|
|
2080
|
+
function copyRegistrySecretToNamespace(monorepoEnv) {
|
|
2082
2081
|
if (!isApplicable()) return;
|
|
2083
|
-
const cmd = kubectlCommand(
|
|
2082
|
+
const cmd = kubectlCommand(`get secret ${SECRET_NAME} -o json`, {
|
|
2084
2083
|
monorepoEnv,
|
|
2085
|
-
namespace:
|
|
2084
|
+
namespace: SOURCE_NAMESPACE
|
|
2086
2085
|
});
|
|
2087
2086
|
const secretStr = new CommandExecutor(cmd, { quiet: true }).exec();
|
|
2088
2087
|
const secretJson = JSON.parse(secretStr);
|
|
@@ -2106,7 +2105,7 @@ function copySecretHarborToNamespace(monorepoEnv) {
|
|
|
2106
2105
|
function patchServiceAccountImagePullSecret(monorepoEnv) {
|
|
2107
2106
|
if (!isApplicable()) return;
|
|
2108
2107
|
const cmd = kubectlCommand(
|
|
2109
|
-
`patch serviceaccount default -p '{"imagePullSecrets": [{"name": "
|
|
2108
|
+
`patch serviceaccount default -p '{"imagePullSecrets": [{"name": "${SECRET_NAME}"}]}'`,
|
|
2110
2109
|
{ monorepoEnv }
|
|
2111
2110
|
);
|
|
2112
2111
|
new CommandExecutor(cmd, { quiet: true }).exec();
|
|
@@ -2127,8 +2126,8 @@ GENERAL USAGE
|
|
|
2127
2126
|
|
|
2128
2127
|
'create' does the following:
|
|
2129
2128
|
1. Creates the namepace
|
|
2130
|
-
2. Creates a secret to hold environment variables (used by devops env) and the base cryptographic secret
|
|
2131
|
-
3.
|
|
2129
|
+
2. Creates a secret to hold environment variables (used by devops env) and the base cryptographic secret
|
|
2130
|
+
3. If use-image-pull-secret is true, copies the external-registry-secret to the namespace and patches the default service account to use it
|
|
2132
2131
|
|
|
2133
2132
|
'delete' removes the namespace in kubernetes, which deletes all entities within it.
|
|
2134
2133
|
|
|
@@ -2143,7 +2142,7 @@ var handlers4 = {
|
|
|
2143
2142
|
createNamespace(env2);
|
|
2144
2143
|
createEmptyEnvSecret(env2);
|
|
2145
2144
|
patchBaseSecret(env2);
|
|
2146
|
-
|
|
2145
|
+
copyRegistrySecretToNamespace(env2);
|
|
2147
2146
|
patchServiceAccountImagePullSecret(env2);
|
|
2148
2147
|
},
|
|
2149
2148
|
delete(opts) {
|
|
@@ -2322,8 +2321,8 @@ function stargGarbageCollection(registryName) {
|
|
|
2322
2321
|
new CommandExecutor(cmd).exec();
|
|
2323
2322
|
}
|
|
2324
2323
|
function prune(registryFullName, repoName, image2) {
|
|
2325
|
-
const
|
|
2326
|
-
if (
|
|
2324
|
+
const registryInfra = getConst("registry-infra");
|
|
2325
|
+
if (registryInfra !== "digitalocean") {
|
|
2327
2326
|
console.warn(
|
|
2328
2327
|
"Pruning is only supported for the DigitalOcean container registry"
|
|
2329
2328
|
);
|
|
@@ -2375,7 +2374,7 @@ USAGE
|
|
|
2375
2374
|
Prunes the repository of old images to enforce the "image-versions-to-keep" constant in config/constants.yaml:
|
|
2376
2375
|
devops registry prune <image> --env <env>
|
|
2377
2376
|
|
|
2378
|
-
This is only relevant when the "infra" constant is set to "digitalocean".
|
|
2377
|
+
This is only relevant when the "registry-infra" constant is set to "digitalocean".
|
|
2379
2378
|
|
|
2380
2379
|
EXAMPLES
|
|
2381
2380
|
${keyExamples14}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ declare const SUPPORTED_LANGUAGES: readonly ["python", "node"];
|
|
|
4
4
|
type SupportedLanguages = typeof SUPPORTED_LANGUAGES[number];
|
|
5
5
|
declare const constFileSchema: z.ZodObject<{
|
|
6
6
|
"project-name": z.ZodString;
|
|
7
|
-
infra: z.ZodEnum<["
|
|
7
|
+
"registry-infra": z.ZodEnum<["digitalocean", "gcp", "harbor"]>;
|
|
8
|
+
"use-image-pull-secret": z.ZodOptional<z.ZodBoolean>;
|
|
8
9
|
"image-versions-to-keep": z.ZodOptional<z.ZodNumber>;
|
|
9
10
|
"registry-base-url": z.ZodString;
|
|
10
11
|
"registry-image-path-prefix": z.ZodOptional<z.ZodString>;
|
|
@@ -14,20 +15,22 @@ declare const constFileSchema: z.ZodObject<{
|
|
|
14
15
|
extensions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
15
16
|
}, "strip", z.ZodTypeAny, {
|
|
16
17
|
"project-name": string;
|
|
17
|
-
infra: "
|
|
18
|
+
"registry-infra": "digitalocean" | "gcp" | "harbor";
|
|
18
19
|
"registry-base-url": string;
|
|
19
20
|
"extra-remote-environments": string[];
|
|
20
21
|
"extra-local-environments": string[];
|
|
22
|
+
"use-image-pull-secret"?: boolean | undefined;
|
|
21
23
|
"image-versions-to-keep"?: number | undefined;
|
|
22
24
|
"registry-image-path-prefix"?: string | undefined;
|
|
23
25
|
"cloudrun-artifact-registry-repo-path"?: string | undefined;
|
|
24
26
|
extensions?: string[] | undefined;
|
|
25
27
|
}, {
|
|
26
28
|
"project-name": string;
|
|
27
|
-
infra: "
|
|
29
|
+
"registry-infra": "digitalocean" | "gcp" | "harbor";
|
|
28
30
|
"registry-base-url": string;
|
|
29
31
|
"extra-remote-environments": string[];
|
|
30
32
|
"extra-local-environments": string[];
|
|
33
|
+
"use-image-pull-secret"?: boolean | undefined;
|
|
31
34
|
"image-versions-to-keep"?: number | undefined;
|
|
32
35
|
"registry-image-path-prefix"?: string | undefined;
|
|
33
36
|
"cloudrun-artifact-registry-repo-path"?: string | undefined;
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
InternalToken,
|
|
3
3
|
decryptAes256Gcm,
|
|
4
4
|
encryptAes256Gcm
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-UZAJJUGJ.js";
|
|
6
6
|
import {
|
|
7
7
|
SUPPORTED_LANGUAGES,
|
|
8
8
|
constFileSchema,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
packageFileNodeSchema,
|
|
11
11
|
packageFilePythonSchema,
|
|
12
12
|
workspaces
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-6FEVIEFY.js";
|
|
14
14
|
|
|
15
15
|
// src/app-support/discovery/dev-discovery-loader.ts
|
|
16
16
|
var _portLookupByServiceName = null;
|
package/dist/plugins.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# These will be used when generating kubernetes entities
|
|
2
2
|
project-name: $PROJECT_NAME
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
infra: digitalocean
|
|
4
|
+
# Registry infrastructure: digitalocean, gcp, or harbor
|
|
5
|
+
registry-infra: digitalocean
|
|
6
6
|
|
|
7
7
|
# Only relevant for Digital Ocean. Determines the number of versions to keep for each docker image.
|
|
8
8
|
image-versions-to-keep: 5
|
package/dist/src/target-templates/infra-variants/digitalocean/.github/workflows/k8s-build.yaml
CHANGED
|
@@ -9,7 +9,7 @@ on:
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
11
|
packages: read
|
|
12
|
-
# For
|
|
12
|
+
# For OIDC authentication to GCP
|
|
13
13
|
# id-token: write
|
|
14
14
|
|
|
15
15
|
jobs:
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
fetch-depth: 50
|
|
30
30
|
|
|
31
31
|
- name: Setup prerequesites
|
|
32
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
32
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
33
33
|
|
|
34
34
|
- name: Connect to DigitalOcean K8s
|
|
35
35
|
uses: ./.github/actions/k8s/connect-to-digitalocean-k8s@v1
|
|
@@ -42,16 +42,16 @@ jobs:
|
|
|
42
42
|
with:
|
|
43
43
|
access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
44
44
|
|
|
45
|
-
# For
|
|
46
|
-
# - name: Connect to
|
|
47
|
-
# uses: ./.github/actions/connect-to-
|
|
45
|
+
# For GCP Artifact Registry with OIDC (alternative to DOCR)
|
|
46
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
47
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
48
48
|
# with:
|
|
49
49
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
50
50
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
51
51
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
52
52
|
|
|
53
53
|
- name: Build image
|
|
54
|
-
uses: ./.github/actions/build-image@v1
|
|
54
|
+
uses: ./.github/actions/common/build-image@v1
|
|
55
55
|
with:
|
|
56
56
|
image_name: ${{ matrix.image_name }}
|
|
57
57
|
cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
|
|
@@ -67,7 +67,7 @@ jobs:
|
|
|
67
67
|
fetch-depth: 50
|
|
68
68
|
|
|
69
69
|
- name: Setup prerequesites
|
|
70
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
70
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
71
71
|
|
|
72
72
|
- name: Connect to DigitalOcean K8s
|
|
73
73
|
uses: ./.github/actions/k8s/connect-to-digitalocean-k8s@v1
|
|
@@ -80,22 +80,22 @@ jobs:
|
|
|
80
80
|
with:
|
|
81
81
|
access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
82
82
|
|
|
83
|
-
# For
|
|
84
|
-
# - name: Connect to
|
|
85
|
-
# uses: ./.github/actions/connect-to-
|
|
83
|
+
# For GCP Artifact Registry with OIDC (alternative to DOCR)
|
|
84
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
85
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
86
86
|
# with:
|
|
87
87
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
88
88
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
89
89
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
90
90
|
|
|
91
91
|
- name: Run DB Migrate
|
|
92
|
-
uses: ./.github/actions/db-migrate@v1
|
|
92
|
+
uses: ./.github/actions/common/db-migrate@v1
|
|
93
93
|
|
|
94
94
|
# Repeat per image (it checks if the image is affected and deploys it if it is)
|
|
95
95
|
- name: Deploy main node
|
|
96
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
96
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
97
97
|
with: { "image_name": "main-node" }
|
|
98
98
|
|
|
99
99
|
- name: Deploy main python
|
|
100
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
100
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
101
101
|
with: { "image_name": "main-python" }
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# These will be used when generating kubernetes entities
|
|
2
2
|
project-name: $PROJECT_NAME
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
infra:
|
|
4
|
+
# Registry infrastructure: digitalocean, gcp, or harbor
|
|
5
|
+
registry-infra: gcp
|
|
6
6
|
|
|
7
7
|
registry-base-url: gcr.io
|
|
8
8
|
# What comes before <image-name>:<tag>. Can be empty.
|
|
@@ -9,7 +9,7 @@ on:
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
11
|
packages: read
|
|
12
|
-
# For
|
|
12
|
+
# For OIDC authentication to GCP
|
|
13
13
|
# id-token: write
|
|
14
14
|
|
|
15
15
|
jobs:
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
fetch-depth: 50
|
|
30
30
|
|
|
31
31
|
- name: Setup prerequesites
|
|
32
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
32
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
33
33
|
|
|
34
34
|
- name: Connect to GKE
|
|
35
35
|
uses: ./.github/actions/k8s/connect-to-gke@v1
|
|
@@ -40,22 +40,22 @@ jobs:
|
|
|
40
40
|
service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
|
|
41
41
|
|
|
42
42
|
- name: Connect to Artifact Registry
|
|
43
|
-
uses: ./.github/actions/registry/connect-to-artifact-registry@v1
|
|
43
|
+
uses: ./.github/actions/registry/connect-to-artifact-registry-with-sa@v1
|
|
44
44
|
with:
|
|
45
45
|
service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
|
|
46
46
|
project_id: ${{ secrets.GCLOUD_PROJECT_ID }}
|
|
47
47
|
region: ${{ secrets.GCLOUD_ARTIFACT_REGISTRY_REGION }}
|
|
48
48
|
|
|
49
|
-
# For
|
|
50
|
-
# - name: Connect to
|
|
51
|
-
# uses: ./.github/actions/connect-to-
|
|
49
|
+
# For GCP Artifact Registry with OIDC (alternative to service account key)
|
|
50
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
51
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
52
52
|
# with:
|
|
53
53
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
54
54
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
55
55
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
56
56
|
|
|
57
57
|
- name: Build image
|
|
58
|
-
uses: ./.github/actions/build-image@v1
|
|
58
|
+
uses: ./.github/actions/common/build-image@v1
|
|
59
59
|
with:
|
|
60
60
|
image_name: ${{ matrix.image_name }}
|
|
61
61
|
cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
|
|
@@ -71,7 +71,7 @@ jobs:
|
|
|
71
71
|
fetch-depth: 50
|
|
72
72
|
|
|
73
73
|
- name: Setup prerequesites
|
|
74
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
74
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
75
75
|
|
|
76
76
|
- name: Connect to GKE
|
|
77
77
|
uses: ./.github/actions/k8s/connect-to-gke@v1
|
|
@@ -82,28 +82,28 @@ jobs:
|
|
|
82
82
|
service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
|
|
83
83
|
|
|
84
84
|
- name: Connect to Artifact Registry
|
|
85
|
-
uses: ./.github/actions/registry/connect-to-artifact-registry@v1
|
|
85
|
+
uses: ./.github/actions/registry/connect-to-artifact-registry-with-sa@v1
|
|
86
86
|
with:
|
|
87
87
|
service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
|
|
88
88
|
project_id: ${{ secrets.GCLOUD_PROJECT_ID }}
|
|
89
89
|
region: ${{ secrets.GCLOUD_ARTIFACT_REGISTRY_REGION }}
|
|
90
90
|
|
|
91
|
-
# For
|
|
92
|
-
# - name: Connect to
|
|
93
|
-
# uses: ./.github/actions/connect-to-
|
|
91
|
+
# For GCP Artifact Registry with OIDC (alternative to service account key)
|
|
92
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
93
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
94
94
|
# with:
|
|
95
95
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
96
96
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
97
97
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
98
98
|
|
|
99
99
|
- name: Run DB Migrate
|
|
100
|
-
uses: ./.github/actions/db-migrate@v1
|
|
100
|
+
uses: ./.github/actions/common/db-migrate@v1
|
|
101
101
|
|
|
102
102
|
# Repeat per image (it checks if the image is affected and deploys it if it is)
|
|
103
103
|
- name: Deploy main node
|
|
104
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
104
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
105
105
|
with: { "image_name": "main-node" }
|
|
106
106
|
|
|
107
107
|
- name: Deploy main python
|
|
108
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
108
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
109
109
|
with: { "image_name": "main-python" }
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# These will be used when generating kubernetes entities
|
|
2
2
|
project-name: $PROJECT_NAME
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
infra:
|
|
4
|
+
# Registry infrastructure: digitalocean, gcp, or harbor
|
|
5
|
+
registry-infra: harbor
|
|
6
|
+
|
|
7
|
+
# When true, devops namespace create will copy external-registry-secret from default namespace
|
|
8
|
+
# and patch the default service account to use it. See docs/infra/RegistrySetup.md for details.
|
|
9
|
+
use-image-pull-secret: true
|
|
6
10
|
|
|
7
11
|
# Only relevant for Digital Ocean. Determines the number of versions to keep for each docker image.
|
|
8
12
|
image-versions-to-keep: 5
|
|
@@ -9,7 +9,7 @@ on:
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
11
|
packages: read
|
|
12
|
-
# For
|
|
12
|
+
# For OIDC authentication to GCP
|
|
13
13
|
# id-token: write
|
|
14
14
|
|
|
15
15
|
jobs:
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
fetch-depth: 50
|
|
30
30
|
|
|
31
31
|
- name: Setup prerequesites
|
|
32
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
32
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
33
33
|
|
|
34
34
|
- name: Connect to Hetzner K8s
|
|
35
35
|
uses: ./.github/actions/k8s/connect-to-hetzner-k8s@v1
|
|
@@ -42,16 +42,16 @@ jobs:
|
|
|
42
42
|
harbor_user: ${{ secrets.HARBOR_USER }}
|
|
43
43
|
harbor_password: ${{ secrets.HARBOR_PASSWORD }}
|
|
44
44
|
|
|
45
|
-
# For
|
|
46
|
-
# - name: Connect to
|
|
47
|
-
# uses: ./.github/actions/connect-to-
|
|
45
|
+
# For GCP Artifact Registry with OIDC (alternative to Harbor)
|
|
46
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
47
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
48
48
|
# with:
|
|
49
49
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
50
50
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
51
51
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
52
52
|
|
|
53
53
|
- name: Build image
|
|
54
|
-
uses: ./.github/actions/build-image@v1
|
|
54
|
+
uses: ./.github/actions/common/build-image@v1
|
|
55
55
|
with:
|
|
56
56
|
image_name: ${{ matrix.image_name }}
|
|
57
57
|
cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
|
|
@@ -67,7 +67,7 @@ jobs:
|
|
|
67
67
|
fetch-depth: 50
|
|
68
68
|
|
|
69
69
|
- name: Setup prerequesites
|
|
70
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
70
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
71
71
|
|
|
72
72
|
- name: Connect to Hetzner K8s
|
|
73
73
|
uses: ./.github/actions/k8s/connect-to-hetzner-k8s@v1
|
|
@@ -80,22 +80,22 @@ jobs:
|
|
|
80
80
|
harbor_user: ${{ secrets.HARBOR_USER }}
|
|
81
81
|
harbor_password: ${{ secrets.HARBOR_PASSWORD }}
|
|
82
82
|
|
|
83
|
-
# For
|
|
84
|
-
# - name: Connect to
|
|
85
|
-
# uses: ./.github/actions/connect-to-
|
|
83
|
+
# For GCP Artifact Registry with OIDC (alternative to Harbor)
|
|
84
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
85
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
86
86
|
# with:
|
|
87
87
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
88
88
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
89
89
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
90
90
|
|
|
91
91
|
- name: Run DB Migrate
|
|
92
|
-
uses: ./.github/actions/db-migrate@v1
|
|
92
|
+
uses: ./.github/actions/common/db-migrate@v1
|
|
93
93
|
|
|
94
94
|
# Repeat per image (it checks if the image is affected and deploys it if it is)
|
|
95
95
|
- name: Deploy main node
|
|
96
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
96
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
97
97
|
with: { "image_name": "main-node" }
|
|
98
98
|
|
|
99
99
|
- name: Deploy main python
|
|
100
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
100
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
101
101
|
with: { "image_name": "main-python" }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: "Connect to Artifact Registry with OIDC"
|
|
2
|
+
description: "Authenticates to Google Artifact Registry using Workload Identity Federation (OIDC)"
|
|
3
|
+
inputs:
|
|
4
|
+
project_id:
|
|
5
|
+
description: "Google Cloud project ID"
|
|
6
|
+
required: true
|
|
7
|
+
project_number:
|
|
8
|
+
description: "Google Cloud project number"
|
|
9
|
+
required: true
|
|
10
|
+
region:
|
|
11
|
+
description: "Google Cloud region where the Artifact Registry is located"
|
|
12
|
+
required: true
|
|
13
|
+
runs:
|
|
14
|
+
using: "composite"
|
|
15
|
+
steps:
|
|
16
|
+
- name: Auth to GCP via OIDC
|
|
17
|
+
uses: google-github-actions/auth@v2
|
|
18
|
+
with:
|
|
19
|
+
workload_identity_provider: projects/${{ inputs.project_number }}/locations/global/workloadIdentityPools/github/providers/github-oidc
|
|
20
|
+
service_account: gha-deployer@${{ inputs.project_id }}.iam.gserviceaccount.com
|
|
21
|
+
project_id: ${{ inputs.project_id }}
|
|
22
|
+
|
|
23
|
+
- name: Setup gcloud
|
|
24
|
+
uses: google-github-actions/setup-gcloud@v2
|
|
25
|
+
|
|
26
|
+
- name: Configure docker to use Artifact Registry
|
|
27
|
+
shell: bash
|
|
28
|
+
run: gcloud auth configure-docker ${{ inputs.region }}-docker.pkg.dev --quiet
|
|
29
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
name: "Connect to Artifact Registry"
|
|
2
|
-
description: "Authenticates to Google Artifact Registry"
|
|
1
|
+
name: "Connect to Artifact Registry with Service Account"
|
|
2
|
+
description: "Authenticates to Google Artifact Registry using a service account JSON key"
|
|
3
3
|
inputs:
|
|
4
4
|
service_account_key:
|
|
5
5
|
description: "Google Cloud service account key in JSON format"
|
package/package.json
CHANGED
package/src/cli/core/constant.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { getConst } from "../../libs/config";
|
|
|
2
2
|
import { CLICommandParser, printUsageAndExit } from "../common";
|
|
3
3
|
|
|
4
4
|
const oneLiner = "Prints to stdout a constant from constant.yaml";
|
|
5
|
-
const keyExamples = `$ devops constant infra`;
|
|
5
|
+
const keyExamples = `$ devops constant registry-infra`;
|
|
6
6
|
|
|
7
7
|
const usage = `
|
|
8
8
|
${oneLiner}
|
package/src/cli/core/init.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { InitGenerator, type InitGeneratorFileInfo } from "../../libs/init-gener
|
|
|
3
3
|
import { CLICommandParser, printUsageAndExit } from "../common";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import fs from 'fs-extra';
|
|
6
|
-
import type { ConstFileSchema } from "../../types";
|
|
7
6
|
|
|
8
7
|
const oneLiner =
|
|
9
8
|
"Initializes the devops utility by copying template files to the current folder";
|
|
@@ -40,14 +39,14 @@ async function createFiles() {
|
|
|
40
39
|
tc.setMessageGenerator(".envrc", envrcMessage);
|
|
41
40
|
|
|
42
41
|
// gitignore
|
|
43
|
-
const gitIgnore = gitIgnoreContent(userChoices.
|
|
42
|
+
const gitIgnore = gitIgnoreContent(userChoices.infraPreset, userChoices.usePython)
|
|
44
43
|
tc.addGeneratedFile(".gitignore", gitIgnore);
|
|
45
44
|
tc.setMessageGenerator(".gitignore", gitignoreMessageGen(gitIgnore));
|
|
46
45
|
|
|
47
46
|
// Infra variants
|
|
48
|
-
tc.addCopiedFolder(`infra-variants/${userChoices.
|
|
47
|
+
tc.addCopiedFolder(`infra-variants/${userChoices.infraPreset}`, ".");
|
|
49
48
|
tc.enableSubtitution(".devops/config/constants.yaml");
|
|
50
|
-
if (userChoices.
|
|
49
|
+
if (userChoices.infraPreset === "hetzner") {
|
|
51
50
|
tc.enableSubtitution(".devops/infra/hetzner/harbor-cert.yaml");
|
|
52
51
|
tc.enableSubtitution(".devops/infra/hetzner/harbor-values.yaml");
|
|
53
52
|
tc.enableSubtitution(".devops/infra/hetzner/hcloud-config.yaml");
|
|
@@ -119,13 +118,13 @@ function packageJsonMessage(usePrisma: boolean) {
|
|
|
119
118
|
],`)}`
|
|
120
119
|
}
|
|
121
120
|
|
|
122
|
-
function gitIgnoreContent(
|
|
121
|
+
function gitIgnoreContent(infraPreset: InfraPreset, usePython: boolean) {
|
|
123
122
|
const common = `**/.env*
|
|
124
123
|
config/kubeconfig
|
|
125
124
|
tmp/**
|
|
126
125
|
!tmp/**/.gitkeep`;
|
|
127
126
|
|
|
128
|
-
const gcloud =
|
|
127
|
+
const gcloud = infraPreset === 'gcloud'
|
|
129
128
|
? 'config/gke_gcloud_auth_plugin_cache'
|
|
130
129
|
: null;
|
|
131
130
|
|
|
@@ -156,11 +155,13 @@ ${chalk.yellow(content)}`;
|
|
|
156
155
|
}
|
|
157
156
|
}
|
|
158
157
|
|
|
158
|
+
type InfraPreset = "gcloud" | "digitalocean" | "hetzner";
|
|
159
|
+
|
|
159
160
|
type UserChoices = {
|
|
160
161
|
projectName: string;
|
|
161
162
|
stagingDomain: string;
|
|
162
163
|
productionDomain: string;
|
|
163
|
-
|
|
164
|
+
infraPreset: InfraPreset;
|
|
164
165
|
gcloudProjectId?: string;
|
|
165
166
|
registryImagePathPrefix?: string;
|
|
166
167
|
registryBaseUrl?: string;
|
|
@@ -193,12 +194,12 @@ function getUserChoices(projectName: string | undefined): Promise<UserChoices> {
|
|
|
193
194
|
},
|
|
194
195
|
{
|
|
195
196
|
type: "list",
|
|
196
|
-
name: "
|
|
197
|
-
message: "
|
|
197
|
+
name: "infraPreset",
|
|
198
|
+
message: "Select your infrastructure preset:",
|
|
198
199
|
choices: [
|
|
199
|
-
{ name: "Google Cloud", value: "gcloud" },
|
|
200
|
-
{ name: "Digital Ocean", value: "digitalocean" },
|
|
201
|
-
{ name: "Hetzner", value: "hetzner" },
|
|
200
|
+
{ name: "Google Cloud (GKE + GCP Registry)", value: "gcloud" },
|
|
201
|
+
{ name: "Digital Ocean (DO K8s + DO Registry)", value: "digitalocean" },
|
|
202
|
+
{ name: "Hetzner (Hetzner K8s + Harbor)", value: "hetzner" },
|
|
202
203
|
],
|
|
203
204
|
},
|
|
204
205
|
{
|
|
@@ -206,21 +207,21 @@ function getUserChoices(projectName: string | undefined): Promise<UserChoices> {
|
|
|
206
207
|
name: "gcloudProjectId",
|
|
207
208
|
message: "Enter the GCP project ID (default: 'changeme')",
|
|
208
209
|
default: "changeme",
|
|
209
|
-
when: (answers) => answers.
|
|
210
|
+
when: (answers) => answers.infraPreset === "gcloud",
|
|
210
211
|
},
|
|
211
212
|
{
|
|
212
213
|
type: "input",
|
|
213
214
|
name: "registryImagePathPrefix",
|
|
214
215
|
message: (answers) => `Enter your Digital Ocean container registry name (default: '${answers.projectName}')`,
|
|
215
216
|
default: (answers) => answers.projectName,
|
|
216
|
-
when: (answers) => answers.
|
|
217
|
+
when: (answers) => answers.infraPreset === "digitalocean",
|
|
217
218
|
},
|
|
218
219
|
{
|
|
219
220
|
type: "input",
|
|
220
221
|
name: "registryBaseUrl",
|
|
221
222
|
message: (answers) => `Enter your registry base URL (default: 'registry.${answers.stagingDomain}')`,
|
|
222
223
|
default: (answers) => `registry.${answers.stagingDomain}`,
|
|
223
|
-
when: (answers) => answers.
|
|
224
|
+
when: (answers) => answers.infraPreset === "hetzner",
|
|
224
225
|
},
|
|
225
226
|
{
|
|
226
227
|
type: "confirm",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CLICommandParser, printUsageAndExit, StrongParams } from "../../../src/cli/common";
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
copyRegistrySecretToNamespace,
|
|
4
4
|
patchServiceAccountImagePullSecret,
|
|
5
|
-
} from "../../../src/libs/
|
|
5
|
+
} from "../../../src/libs/registry/image-pull-secret";
|
|
6
6
|
import { checkEnvSetup, createEmptyEnvSecret, createNamespace, deleteNamespace, patchBaseSecret } from "../../libs/k8s-namespace";
|
|
7
7
|
|
|
8
8
|
const oneLiner = "Creates the basic prerequisites for a monorepo";
|
|
@@ -20,8 +20,8 @@ GENERAL USAGE
|
|
|
20
20
|
|
|
21
21
|
'create' does the following:
|
|
22
22
|
1. Creates the namepace
|
|
23
|
-
2. Creates a secret to hold environment variables (used by devops env) and the base cryptographic secret
|
|
24
|
-
3.
|
|
23
|
+
2. Creates a secret to hold environment variables (used by devops env) and the base cryptographic secret
|
|
24
|
+
3. If use-image-pull-secret is true, copies the external-registry-secret to the namespace and patches the default service account to use it
|
|
25
25
|
|
|
26
26
|
'delete' removes the namespace in kubernetes, which deletes all entities within it.
|
|
27
27
|
|
|
@@ -37,7 +37,7 @@ const handlers = {
|
|
|
37
37
|
createNamespace(env);
|
|
38
38
|
createEmptyEnvSecret(env);
|
|
39
39
|
patchBaseSecret(env);
|
|
40
|
-
|
|
40
|
+
copyRegistrySecretToNamespace(env);
|
|
41
41
|
patchServiceAccountImagePullSecret(env);
|
|
42
42
|
},
|
|
43
43
|
delete (opts: StrongParams) {
|
package/src/cli/core/registry.ts
CHANGED
|
@@ -35,7 +35,7 @@ USAGE
|
|
|
35
35
|
Prunes the repository of old images to enforce the "image-versions-to-keep" constant in config/constants.yaml:
|
|
36
36
|
devops registry prune <image> --env <env>
|
|
37
37
|
|
|
38
|
-
This is only relevant when the "infra" constant is set to "digitalocean".
|
|
38
|
+
This is only relevant when the "registry-infra" constant is set to "digitalocean".
|
|
39
39
|
|
|
40
40
|
EXAMPLES
|
|
41
41
|
${keyExamples}
|
|
@@ -63,8 +63,8 @@ export function prune(
|
|
|
63
63
|
repoName: string,
|
|
64
64
|
image: string
|
|
65
65
|
) {
|
|
66
|
-
const
|
|
67
|
-
if (
|
|
66
|
+
const registryInfra = getConst("registry-infra");
|
|
67
|
+
if (registryInfra !== "digitalocean") {
|
|
68
68
|
console.warn(
|
|
69
69
|
"Pruning is only supported for the DigitalOcean container registry"
|
|
70
70
|
);
|
|
@@ -3,23 +3,23 @@ import { getConst } from "../config";
|
|
|
3
3
|
import { envToNamespace } from "../k8s-constants";
|
|
4
4
|
import { kubectlCommand } from "../k8s-helpers";
|
|
5
5
|
|
|
6
|
+
const SECRET_NAME = "external-registry-secret";
|
|
7
|
+
const SOURCE_NAMESPACE = "default";
|
|
8
|
+
|
|
6
9
|
function isApplicable() {
|
|
7
|
-
const
|
|
8
|
-
if (
|
|
9
|
-
console.warn(
|
|
10
|
-
"Setting up registry permissions is only needed for Harbor in a Hetzner setup"
|
|
11
|
-
);
|
|
10
|
+
const useImagePullSecret = getConst("use-image-pull-secret");
|
|
11
|
+
if (!useImagePullSecret) {
|
|
12
12
|
return false;
|
|
13
13
|
}
|
|
14
14
|
return true;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export function
|
|
17
|
+
export function copyRegistrySecretToNamespace(monorepoEnv: string) {
|
|
18
18
|
if (!isApplicable()) return;
|
|
19
19
|
|
|
20
|
-
const cmd = kubectlCommand(
|
|
20
|
+
const cmd = kubectlCommand(`get secret ${SECRET_NAME} -o json`, {
|
|
21
21
|
monorepoEnv,
|
|
22
|
-
namespace:
|
|
22
|
+
namespace: SOURCE_NAMESPACE,
|
|
23
23
|
});
|
|
24
24
|
const secretStr = new CommandExecutor(cmd, { quiet: true }).exec();
|
|
25
25
|
const secretJson = JSON.parse(secretStr);
|
|
@@ -47,7 +47,7 @@ export function patchServiceAccountImagePullSecret(monorepoEnv: string) {
|
|
|
47
47
|
if (!isApplicable()) return;
|
|
48
48
|
|
|
49
49
|
const cmd = kubectlCommand(
|
|
50
|
-
`patch serviceaccount default -p '{"imagePullSecrets": [{"name": "
|
|
50
|
+
`patch serviceaccount default -p '{"imagePullSecrets": [{"name": "${SECRET_NAME}"}]}'`,
|
|
51
51
|
{ monorepoEnv }
|
|
52
52
|
);
|
|
53
53
|
new CommandExecutor(cmd, { quiet: true }).exec();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# These will be used when generating kubernetes entities
|
|
2
2
|
project-name: $PROJECT_NAME
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
infra: digitalocean
|
|
4
|
+
# Registry infrastructure: digitalocean, gcp, or harbor
|
|
5
|
+
registry-infra: digitalocean
|
|
6
6
|
|
|
7
7
|
# Only relevant for Digital Ocean. Determines the number of versions to keep for each docker image.
|
|
8
8
|
image-versions-to-keep: 5
|
|
@@ -9,7 +9,7 @@ on:
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
11
|
packages: read
|
|
12
|
-
# For
|
|
12
|
+
# For OIDC authentication to GCP
|
|
13
13
|
# id-token: write
|
|
14
14
|
|
|
15
15
|
jobs:
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
fetch-depth: 50
|
|
30
30
|
|
|
31
31
|
- name: Setup prerequesites
|
|
32
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
32
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
33
33
|
|
|
34
34
|
- name: Connect to DigitalOcean K8s
|
|
35
35
|
uses: ./.github/actions/k8s/connect-to-digitalocean-k8s@v1
|
|
@@ -42,16 +42,16 @@ jobs:
|
|
|
42
42
|
with:
|
|
43
43
|
access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
44
44
|
|
|
45
|
-
# For
|
|
46
|
-
# - name: Connect to
|
|
47
|
-
# uses: ./.github/actions/connect-to-
|
|
45
|
+
# For GCP Artifact Registry with OIDC (alternative to DOCR)
|
|
46
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
47
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
48
48
|
# with:
|
|
49
49
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
50
50
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
51
51
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
52
52
|
|
|
53
53
|
- name: Build image
|
|
54
|
-
uses: ./.github/actions/build-image@v1
|
|
54
|
+
uses: ./.github/actions/common/build-image@v1
|
|
55
55
|
with:
|
|
56
56
|
image_name: ${{ matrix.image_name }}
|
|
57
57
|
cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
|
|
@@ -67,7 +67,7 @@ jobs:
|
|
|
67
67
|
fetch-depth: 50
|
|
68
68
|
|
|
69
69
|
- name: Setup prerequesites
|
|
70
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
70
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
71
71
|
|
|
72
72
|
- name: Connect to DigitalOcean K8s
|
|
73
73
|
uses: ./.github/actions/k8s/connect-to-digitalocean-k8s@v1
|
|
@@ -80,22 +80,22 @@ jobs:
|
|
|
80
80
|
with:
|
|
81
81
|
access_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
82
82
|
|
|
83
|
-
# For
|
|
84
|
-
# - name: Connect to
|
|
85
|
-
# uses: ./.github/actions/connect-to-
|
|
83
|
+
# For GCP Artifact Registry with OIDC (alternative to DOCR)
|
|
84
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
85
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
86
86
|
# with:
|
|
87
87
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
88
88
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
89
89
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
90
90
|
|
|
91
91
|
- name: Run DB Migrate
|
|
92
|
-
uses: ./.github/actions/db-migrate@v1
|
|
92
|
+
uses: ./.github/actions/common/db-migrate@v1
|
|
93
93
|
|
|
94
94
|
# Repeat per image (it checks if the image is affected and deploys it if it is)
|
|
95
95
|
- name: Deploy main node
|
|
96
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
96
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
97
97
|
with: { "image_name": "main-node" }
|
|
98
98
|
|
|
99
99
|
- name: Deploy main python
|
|
100
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
100
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
101
101
|
with: { "image_name": "main-python" }
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# These will be used when generating kubernetes entities
|
|
2
2
|
project-name: $PROJECT_NAME
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
infra:
|
|
4
|
+
# Registry infrastructure: digitalocean, gcp, or harbor
|
|
5
|
+
registry-infra: gcp
|
|
6
6
|
|
|
7
7
|
registry-base-url: gcr.io
|
|
8
8
|
# What comes before <image-name>:<tag>. Can be empty.
|
|
@@ -9,7 +9,7 @@ on:
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
11
|
packages: read
|
|
12
|
-
# For
|
|
12
|
+
# For OIDC authentication to GCP
|
|
13
13
|
# id-token: write
|
|
14
14
|
|
|
15
15
|
jobs:
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
fetch-depth: 50
|
|
30
30
|
|
|
31
31
|
- name: Setup prerequesites
|
|
32
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
32
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
33
33
|
|
|
34
34
|
- name: Connect to GKE
|
|
35
35
|
uses: ./.github/actions/k8s/connect-to-gke@v1
|
|
@@ -40,22 +40,22 @@ jobs:
|
|
|
40
40
|
service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
|
|
41
41
|
|
|
42
42
|
- name: Connect to Artifact Registry
|
|
43
|
-
uses: ./.github/actions/registry/connect-to-artifact-registry@v1
|
|
43
|
+
uses: ./.github/actions/registry/connect-to-artifact-registry-with-sa@v1
|
|
44
44
|
with:
|
|
45
45
|
service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
|
|
46
46
|
project_id: ${{ secrets.GCLOUD_PROJECT_ID }}
|
|
47
47
|
region: ${{ secrets.GCLOUD_ARTIFACT_REGISTRY_REGION }}
|
|
48
48
|
|
|
49
|
-
# For
|
|
50
|
-
# - name: Connect to
|
|
51
|
-
# uses: ./.github/actions/connect-to-
|
|
49
|
+
# For GCP Artifact Registry with OIDC (alternative to service account key)
|
|
50
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
51
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
52
52
|
# with:
|
|
53
53
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
54
54
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
55
55
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
56
56
|
|
|
57
57
|
- name: Build image
|
|
58
|
-
uses: ./.github/actions/build-image@v1
|
|
58
|
+
uses: ./.github/actions/common/build-image@v1
|
|
59
59
|
with:
|
|
60
60
|
image_name: ${{ matrix.image_name }}
|
|
61
61
|
cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
|
|
@@ -71,7 +71,7 @@ jobs:
|
|
|
71
71
|
fetch-depth: 50
|
|
72
72
|
|
|
73
73
|
- name: Setup prerequesites
|
|
74
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
74
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
75
75
|
|
|
76
76
|
- name: Connect to GKE
|
|
77
77
|
uses: ./.github/actions/k8s/connect-to-gke@v1
|
|
@@ -82,28 +82,28 @@ jobs:
|
|
|
82
82
|
service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
|
|
83
83
|
|
|
84
84
|
- name: Connect to Artifact Registry
|
|
85
|
-
uses: ./.github/actions/registry/connect-to-artifact-registry@v1
|
|
85
|
+
uses: ./.github/actions/registry/connect-to-artifact-registry-with-sa@v1
|
|
86
86
|
with:
|
|
87
87
|
service_account_key: ${{ secrets.GCLOUD_SA_KEY }}
|
|
88
88
|
project_id: ${{ secrets.GCLOUD_PROJECT_ID }}
|
|
89
89
|
region: ${{ secrets.GCLOUD_ARTIFACT_REGISTRY_REGION }}
|
|
90
90
|
|
|
91
|
-
# For
|
|
92
|
-
# - name: Connect to
|
|
93
|
-
# uses: ./.github/actions/connect-to-
|
|
91
|
+
# For GCP Artifact Registry with OIDC (alternative to service account key)
|
|
92
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
93
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
94
94
|
# with:
|
|
95
95
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
96
96
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
97
97
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
98
98
|
|
|
99
99
|
- name: Run DB Migrate
|
|
100
|
-
uses: ./.github/actions/db-migrate@v1
|
|
100
|
+
uses: ./.github/actions/common/db-migrate@v1
|
|
101
101
|
|
|
102
102
|
# Repeat per image (it checks if the image is affected and deploys it if it is)
|
|
103
103
|
- name: Deploy main node
|
|
104
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
104
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
105
105
|
with: { "image_name": "main-node" }
|
|
106
106
|
|
|
107
107
|
- name: Deploy main python
|
|
108
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
108
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
109
109
|
with: { "image_name": "main-python" }
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# These will be used when generating kubernetes entities
|
|
2
2
|
project-name: $PROJECT_NAME
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
infra:
|
|
4
|
+
# Registry infrastructure: digitalocean, gcp, or harbor
|
|
5
|
+
registry-infra: harbor
|
|
6
|
+
|
|
7
|
+
# When true, devops namespace create will copy external-registry-secret from default namespace
|
|
8
|
+
# and patch the default service account to use it. See docs/infra/RegistrySetup.md for details.
|
|
9
|
+
use-image-pull-secret: true
|
|
6
10
|
|
|
7
11
|
# Only relevant for Digital Ocean. Determines the number of versions to keep for each docker image.
|
|
8
12
|
image-versions-to-keep: 5
|
|
@@ -9,7 +9,7 @@ on:
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
11
|
packages: read
|
|
12
|
-
# For
|
|
12
|
+
# For OIDC authentication to GCP
|
|
13
13
|
# id-token: write
|
|
14
14
|
|
|
15
15
|
jobs:
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
fetch-depth: 50
|
|
30
30
|
|
|
31
31
|
- name: Setup prerequesites
|
|
32
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
32
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
33
33
|
|
|
34
34
|
- name: Connect to Hetzner K8s
|
|
35
35
|
uses: ./.github/actions/k8s/connect-to-hetzner-k8s@v1
|
|
@@ -42,16 +42,16 @@ jobs:
|
|
|
42
42
|
harbor_user: ${{ secrets.HARBOR_USER }}
|
|
43
43
|
harbor_password: ${{ secrets.HARBOR_PASSWORD }}
|
|
44
44
|
|
|
45
|
-
# For
|
|
46
|
-
# - name: Connect to
|
|
47
|
-
# uses: ./.github/actions/connect-to-
|
|
45
|
+
# For GCP Artifact Registry with OIDC (alternative to Harbor)
|
|
46
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
47
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
48
48
|
# with:
|
|
49
49
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
50
50
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
51
51
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
52
52
|
|
|
53
53
|
- name: Build image
|
|
54
|
-
uses: ./.github/actions/build-image@v1
|
|
54
|
+
uses: ./.github/actions/common/build-image@v1
|
|
55
55
|
with:
|
|
56
56
|
image_name: ${{ matrix.image_name }}
|
|
57
57
|
cache_path: ${{ matrix.cache_path || '/root/.bun/install/cache' }}
|
|
@@ -67,7 +67,7 @@ jobs:
|
|
|
67
67
|
fetch-depth: 50
|
|
68
68
|
|
|
69
69
|
- name: Setup prerequesites
|
|
70
|
-
uses: ./.github/actions/setup-prereq@v1
|
|
70
|
+
uses: ./.github/actions/common/setup-prereq@v1
|
|
71
71
|
|
|
72
72
|
- name: Connect to Hetzner K8s
|
|
73
73
|
uses: ./.github/actions/k8s/connect-to-hetzner-k8s@v1
|
|
@@ -80,22 +80,22 @@ jobs:
|
|
|
80
80
|
harbor_user: ${{ secrets.HARBOR_USER }}
|
|
81
81
|
harbor_password: ${{ secrets.HARBOR_PASSWORD }}
|
|
82
82
|
|
|
83
|
-
# For
|
|
84
|
-
# - name: Connect to
|
|
85
|
-
# uses: ./.github/actions/connect-to-
|
|
83
|
+
# For GCP Artifact Registry with OIDC (alternative to Harbor)
|
|
84
|
+
# - name: Connect to Artifact Registry with OIDC
|
|
85
|
+
# uses: ./.github/actions/registry/connect-to-artifact-registry-with-oidc@v1
|
|
86
86
|
# with:
|
|
87
87
|
# project_id: ${{ vars.GCP_PROJECT_ID }}
|
|
88
88
|
# project_number: ${{ vars.GCP_PROJECT_NUMBER }}
|
|
89
89
|
# region: ${{ vars.GCP_ARTIFACT_REGISTRY_REGION }}
|
|
90
90
|
|
|
91
91
|
- name: Run DB Migrate
|
|
92
|
-
uses: ./.github/actions/db-migrate@v1
|
|
92
|
+
uses: ./.github/actions/common/db-migrate@v1
|
|
93
93
|
|
|
94
94
|
# Repeat per image (it checks if the image is affected and deploys it if it is)
|
|
95
95
|
- name: Deploy main node
|
|
96
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
96
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
97
97
|
with: { "image_name": "main-node" }
|
|
98
98
|
|
|
99
99
|
- name: Deploy main python
|
|
100
|
-
uses: ./.github/actions/deploy-image-k8s@v1
|
|
100
|
+
uses: ./.github/actions/common/deploy-image-k8s@v1
|
|
101
101
|
with: { "image_name": "main-python" }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: "Connect to Artifact Registry with OIDC"
|
|
2
|
+
description: "Authenticates to Google Artifact Registry using Workload Identity Federation (OIDC)"
|
|
3
|
+
inputs:
|
|
4
|
+
project_id:
|
|
5
|
+
description: "Google Cloud project ID"
|
|
6
|
+
required: true
|
|
7
|
+
project_number:
|
|
8
|
+
description: "Google Cloud project number"
|
|
9
|
+
required: true
|
|
10
|
+
region:
|
|
11
|
+
description: "Google Cloud region where the Artifact Registry is located"
|
|
12
|
+
required: true
|
|
13
|
+
runs:
|
|
14
|
+
using: "composite"
|
|
15
|
+
steps:
|
|
16
|
+
- name: Auth to GCP via OIDC
|
|
17
|
+
uses: google-github-actions/auth@v2
|
|
18
|
+
with:
|
|
19
|
+
workload_identity_provider: projects/${{ inputs.project_number }}/locations/global/workloadIdentityPools/github/providers/github-oidc
|
|
20
|
+
service_account: gha-deployer@${{ inputs.project_id }}.iam.gserviceaccount.com
|
|
21
|
+
project_id: ${{ inputs.project_id }}
|
|
22
|
+
|
|
23
|
+
- name: Setup gcloud
|
|
24
|
+
uses: google-github-actions/setup-gcloud@v2
|
|
25
|
+
|
|
26
|
+
- name: Configure docker to use Artifact Registry
|
|
27
|
+
shell: bash
|
|
28
|
+
run: gcloud auth configure-docker ${{ inputs.region }}-docker.pkg.dev --quiet
|
|
29
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
name: "Connect to Artifact Registry"
|
|
2
|
-
description: "Authenticates to Google Artifact Registry"
|
|
1
|
+
name: "Connect to Artifact Registry with Service Account"
|
|
2
|
+
description: "Authenticates to Google Artifact Registry using a service account JSON key"
|
|
3
3
|
inputs:
|
|
4
4
|
service_account_key:
|
|
5
5
|
description: "Google Cloud service account key in JSON format"
|
package/src/types/index.ts
CHANGED
|
@@ -7,7 +7,8 @@ export type SupportedLanguages = typeof SUPPORTED_LANGUAGES[number];
|
|
|
7
7
|
|
|
8
8
|
export const constFileSchema = z.object({
|
|
9
9
|
"project-name": z.string(),
|
|
10
|
-
"infra": z.enum(["
|
|
10
|
+
"registry-infra": z.enum(["digitalocean", "gcp", "harbor"]),
|
|
11
|
+
"use-image-pull-secret": z.boolean().optional(),
|
|
11
12
|
"image-versions-to-keep": z.number().optional(),
|
|
12
13
|
"registry-base-url": z.string(),
|
|
13
14
|
"registry-image-path-prefix": z.string().optional(),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|