🌳
pt0/deployF/ethF/doSyncPrysmAI.mts
1import * as _ from 'lodash-es'
5import { jwtPath } from './jwtPathF.mts'
16/** GOMEMLIMIT = 85% of the k8s memory limit (in GiB). Forces Go GC before the cgroup OOM killer,
17 * mitigating prysm's heap-growth-to-limit behavior. Only handles `<N>Gi` limits. */
18const goMemLimitFromPodRes = (podResources?: object): string | undefined => {
19 const memLimit = (podResources as {limits?: {memory?: string}})?.limits?.memory
20 const m = memLimit?.match(/^(\d+)Gi$/)
21 return m ? `${Math.floor(Number(m[1]) * 0.85)}GiB` : undefined
24const beaconDeploymentTmpl = ({
25 name, beaconDataPvcName, prysmNodePort, execEngProv, ethNetwork, ethRewardAddr,
26 p2pHostIp, relayHostPort, cpSyncApiUrl, prysmVersion, podResources,
27}: {
28 name: string, beaconDataPvcName: string, prysmNodePort: number, execEngProv: string,
29 ethNetwork: string, ethRewardAddr: string, p2pHostIp: string, relayHostPort: string | null,
30 cpSyncApiUrl: string | null, prysmVersion: string, podResources?: object,
31}) => {
32 const jwtName = `${ethNetwork}-jwt`
33 const image = `gcr.io/prysmaticlabs/prysm/beacon-chain:${prysmVersion}`
34 const goMemLimit = goMemLimitFromPodRes(podResources)
36 let args = [
37 '--datadir=/data',
38 '--rpc-host=0.0.0.0',
39 '--monitoring-host=0.0.0.0',
40 `--execution-endpoint=${execEngProv}`,
41 '--accept-terms-of-use',
42 '--mainnet',
43 '--grpc-gateway-host=0.0.0.0',
44 '--grpc-gateway-port=3500',
45 '--grpc-gateway-corsdomain=*',
46 `--p2p-host-ip=${p2pHostIp}`,
47 `--p2p-tcp-port=${prysmNodePort}`,
48 `--p2p-udp-port=${prysmNodePort}`,
49 `--jwt-secret=${jwtPath}`,
50 `--suggested-fee-recipient=${ethRewardAddr}`,
51 ]
52 if (cpSyncApiUrl) {
53 args = [
54 ...args,
55 `--checkpoint-sync-url=${cpSyncApiUrl}`,
56 `--genesis-beacon-api-url=${cpSyncApiUrl}`,
57 ]
58 }
60 return {
61 apiVersion: 'apps/v1',
62 kind: 'Deployment',
63 metadata: {
64 name
65 },
66 spec: {
67 replicas: 1,
68 strategy: {
69 type: 'Recreate'
70 },
71 selector: {
72 matchLabels: {
73 name
74 }
75 },
76 template: {
77 metadata: {
78 labels: {
79 name
80 }
81 },
82 spec: {
83 containers: [
84 {
85 args, image, command: [],
86 name,
87 resources: podResources,
88 env: goMemLimit ? [{name: 'GOMEMLIMIT', value: goMemLimit}] : undefined,
89 volumeMounts: [
90 {
91 mountPath: '/data',
92 name: beaconDataPvcName
93 },
94 {
95 mountPath: jwtPath,
96 name: jwtName,
97 subPath: jwtName,
98 }
99 ]
100 }
101 ],
102 volumes: [
103 {
104 name: beaconDataPvcName,
105 persistentVolumeClaim: {
106 claimName: beaconDataPvcName
107 }
108 },
109 {
110 name: jwtName,
111 secret: {
112 secretName: jwtName
113 }
114 }
115 ]
116 }
117 }
118 }
119 }
122const validatorDeploymentTmpl = ({name, beaconName, beaconPort, validatorDbPvcName, valsecretsName, walletSecName, prysmVersion, ethRewardAddr}: {
123 name: string, beaconName: string, beaconPort: number, validatorDbPvcName: string,
124 valsecretsName: string, walletSecName: string, prysmVersion: string, ethRewardAddr: string,
125}) => {
126 const {volumeMounts, volumes, passwordFilePath, walletDir} = validatorKeysDeploymentProps({walletSecName, valsecretsName})
128 const image = `gcr.io/prysmaticlabs/prysm/validator:${prysmVersion}`
130 return {
131 apiVersion: 'apps/v1',
132 kind: 'Deployment',
133 metadata: {
134 name
135 },
136 spec: {
137 replicas: 1,
138 selector: {
139 matchLabels: {
140 name
141 }
142 },
143 strategy: {
144 type: 'Recreate'
145 },
146 template: {
147 metadata: {
148 labels: {
149 name
150 }
151 },
152 spec: {
153 containers: [
154 {
155 args: [
156 `--wallet-dir=${walletDir}`,
157 `--wallet-password-file=${passwordFilePath}`,
158 '--mainnet',
159 '--accept-terms-of-use',
160 `--beacon-rpc-provider=${beaconName}:${beaconPort}`,
161 '--datadir=/validatorDB',
162 `--suggested-fee-recipient=${ethRewardAddr}`,
163 ],
164 image,
165 name: 'validator',
166 volumeMounts: [
167 ...volumeMounts,
168 {
169 mountPath: '/validatorDB',
170 name: validatorDbPvcName
171 },
172 ]
173 }
174 ],
175 volumes: [
176 ...volumes,
177 {
178 name: validatorDbPvcName,
179 persistentVolumeClaim: {
180 claimName: validatorDbPvcName
181 }
182 }
183 ]
184 }
185 }
186 }
187 }
190export const doSyncPrysm = async ({
191 eth1ClientName, ethNetwork, enableValidator, ethRewardAddr,
192 p2pHostIp,
193 prysmNodePort, relayHostPort, prysmVersion, cpSyncApiUrl,
194 guardValidatorFn, podResources, ethValidatorNums,
195}: {
196 eth1ClientName: string, ethNetwork: string, enableValidator: boolean, ethRewardAddr: string,
197 p2pHostIp: string, prysmNodePort: number, relayHostPort: string | null, prysmVersion: string,
198 cpSyncApiUrl: string | null, guardValidatorFn?: GuardValidatorFn, podResources?: object, ethValidatorNums?: number[],
199}) => {
200 const {cluster_name, cfApiKeySecretName, domainNames} = getKlusterCtx()
201 const action = getAction()
202 assertDefined(p2pHostIp)
204 const name = `prysm-${ethNetwork}`
205 const beaconName = `beacon-${name}`
206 const beaconPort = 4000
208 const validatorName = `validator-${name}`
209 const validatorDbPvcName = `validatordb2-${name}`
210 const beaconDataPvcName = name
211 const valsecretsName = `valsecrets-${ethNetwork}`
212 const walletSecName = `wallet-${ethNetwork}-direct`
214 let {httpWeb3Prov, execEngProv, jwtSecretName} = getEth2Vals({ethNetwork, eth1ClientName})
216 let resources: any[] = [
217 kubeSvcTmpl({name: validatorName, portNo: 7500}),
219 dualNodePortTmpl({selfName: beaconName + '-p2p', name: beaconName, nodePort: prysmNodePort}),
221 kubeSvcTmpl({name: beaconName, portNos: [beaconPort, 3500]}),
222 beaconDeploymentTmpl({
223 name: beaconName, beaconDataPvcName, prysmNodePort,
224 prysmVersion, execEngProv, ethNetwork, ethRewardAddr,
225 p2pHostIp, podResources,
226 relayHostPort, cpSyncApiUrl,
227 }),
228 secretFileTemplate({name: jwtSecretName as any, kubeName: jwtSecretName}),
229 ]
230 if (enableValidator === true) {
231 assertDefined(guardValidatorFn, {enableValidator})
232 await guardValidatorFn({ethNetwork, name, cluster_name, action})
234 const validatorDeployment = validatorDeploymentTmpl({name: validatorName, validatorDbPvcName, beaconName, beaconPort, valsecretsName, walletSecName, prysmVersion, ethRewardAddr})
235 const claimCheckConfigMap = await withClaimCheck({
236 deployment: validatorDeployment, enabled: action != 'delete',
237 ethValidatorNum: ethValidatorNums?.[0], cluster_name, domainName: domainNames?.[0], cfApiKeySecretName,
238 })
239 resources = _.union(resources, [
240 secretFileTemplate({name: valsecretsName as any, kubeName: valsecretsName}),
241 secretFileTemplate({name: walletSecName as any, kubeName: walletSecName}),
242 validatorDeployment,
243 ...(claimCheckConfigMap ? [claimCheckConfigMap] : []),
244 ])
245 }
247 resources = _.union(resources, cleanupResOnDelete({action, enabled: enableValidator, secNames: [valsecretsName, walletSecName], deployNames: [validatorName]}))
249 resources = [
250 ...resources,
251 ...await genericPvcTmplA({
252 name: beaconDataPvcName,
253 sizeGb: 400,
254 useM2: true, action
255 }),
256 ...(enableValidator || action == 'delete') ? await genericPvcTmplA({name: validatorDbPvcName, sizeGb: 10, action}) : [],
257 ]
259 await guardOnlyRecreateDeploymentsResourcesAction({resources, action, cluster_name})