@@ -23,7 +23,16 @@ import (
2323 "syscall"
2424)
2525
26- const runtimeMetadataPath = "/etc/firework/runtime.json"
26+ const (
27+ runtimeMetadataPath = "/etc/firework/runtime.json"
28+
29+ vmMaxMapCountPath = "/proc/sys/vm/max_map_count"
30+ vmMaxMapCountValue = "262144"
31+ minNoFileLimit = 65535
32+
33+ kibanaUUIDPath = "/usr/share/kibana/data/uuid"
34+ elasticsearchKeystorePath = "/usr/share/elasticsearch/config/elasticsearch.keystore"
35+ )
2736
2837type runtimeMetadata struct {
2938 User string `json:"user,omitempty"`
@@ -35,6 +44,7 @@ type runtimeMetadata struct {
3544func main () {
3645 mountAll ()
3746 setHostname ()
47+ applyRuntimeTuning ()
3848 meta := loadRuntimeMetadata ()
3949 applyImageEnv (meta .Env )
4050 exportFireworkEnv ()
@@ -128,6 +138,8 @@ func execService(meta runtimeMetadata) {
128138 argv = []string {"/sbin/init" }
129139 }
130140
141+ sanitizeRuntimeState ()
142+
131143 if meta .Workdir != "" {
132144 if err := os .Chdir (meta .Workdir ); err != nil {
133145 fmt .Fprintf (os .Stderr , "fc-init: chdir %s: %v\n " , meta .Workdir , err )
@@ -318,3 +330,129 @@ func parseRequiredID(s string) (int, error) {
318330 }
319331 return n , nil
320332}
333+
334+ func applyRuntimeTuning () {
335+ if err := os .WriteFile (vmMaxMapCountPath , []byte (vmMaxMapCountValue ), 0o644 ); err != nil {
336+ fmt .Fprintf (os .Stderr , "fc-init: set vm.max_map_count=%s: %v\n " , vmMaxMapCountValue , err )
337+ }
338+ if err := ensureNoFileLimit (minNoFileLimit ); err != nil {
339+ fmt .Fprintf (os .Stderr , "fc-init: set nofile limit: %v\n " , err )
340+ }
341+ }
342+
343+ func ensureNoFileLimit (min uint64 ) error {
344+ var lim syscall.Rlimit
345+ if err := syscall .Getrlimit (syscall .RLIMIT_NOFILE , & lim ); err != nil {
346+ return fmt .Errorf ("getrlimit: %w" , err )
347+ }
348+
349+ newCur := lim .Cur
350+ newMax := lim .Max
351+ if newCur < min {
352+ newCur = min
353+ }
354+ if newMax < min {
355+ newMax = min
356+ }
357+ if newCur == lim .Cur && newMax == lim .Max {
358+ return nil
359+ }
360+
361+ if err := syscall .Setrlimit (syscall .RLIMIT_NOFILE , & syscall.Rlimit {
362+ Cur : newCur ,
363+ Max : newMax ,
364+ }); err != nil {
365+ return fmt .Errorf ("setrlimit: %w" , err )
366+ }
367+ return nil
368+ }
369+
370+ func sanitizeRuntimeState () {
371+ sanitizeKibanaUUID (kibanaUUIDPath )
372+ sanitizeElasticsearchKeystore (elasticsearchKeystorePath )
373+ }
374+
375+ func sanitizeKibanaUUID (path string ) {
376+ data , ok := readSmallFile (path )
377+ if ! ok {
378+ return
379+ }
380+ uuid := strings .TrimSpace (string (data ))
381+ if uuid == "" || ! isValidUUID (uuid ) {
382+ if err := os .Remove (path ); err != nil && ! os .IsNotExist (err ) {
383+ fmt .Fprintf (os .Stderr , "fc-init: remove invalid kibana uuid %s: %v\n " , path , err )
384+ return
385+ }
386+ fmt .Fprintf (os .Stderr , "fc-init: removed invalid kibana uuid file %s\n " , path )
387+ }
388+ }
389+
390+ func sanitizeElasticsearchKeystore (path string ) {
391+ info , err := os .Stat (path )
392+ if err != nil {
393+ if ! os .IsNotExist (err ) {
394+ fmt .Fprintf (os .Stderr , "fc-init: stat %s: %v\n " , path , err )
395+ }
396+ return
397+ }
398+ if ! info .Mode ().IsRegular () {
399+ return
400+ }
401+ // Elasticsearch expects a non-empty keystore file. Size < 16 strongly
402+ // indicates corruption (e.g. zero-byte files observed in crash loops).
403+ if info .Size () >= 16 {
404+ return
405+ }
406+ if err := os .Remove (path ); err != nil && ! os .IsNotExist (err ) {
407+ fmt .Fprintf (os .Stderr , "fc-init: remove invalid elasticsearch keystore %s: %v\n " , path , err )
408+ return
409+ }
410+ fmt .Fprintf (os .Stderr , "fc-init: removed invalid elasticsearch keystore %s\n " , path )
411+ }
412+
413+ func readSmallFile (path string ) ([]byte , bool ) {
414+ info , err := os .Stat (path )
415+ if err != nil {
416+ if ! os .IsNotExist (err ) {
417+ fmt .Fprintf (os .Stderr , "fc-init: stat %s: %v\n " , path , err )
418+ }
419+ return nil , false
420+ }
421+ if ! info .Mode ().IsRegular () {
422+ return nil , false
423+ }
424+ if info .Size () > 1024 {
425+ fmt .Fprintf (os .Stderr , "fc-init: %s too large for UUID file\n " , path )
426+ return nil , false
427+ }
428+ data , err := os .ReadFile (path )
429+ if err != nil {
430+ fmt .Fprintf (os .Stderr , "fc-init: read %s: %v\n " , path , err )
431+ return nil , false
432+ }
433+ return data , true
434+ }
435+
436+ func isValidUUID (v string ) bool {
437+ if len (v ) != 36 {
438+ return false
439+ }
440+ for i := 0 ; i < len (v ); i ++ {
441+ c := v [i ]
442+ switch i {
443+ case 8 , 13 , 18 , 23 :
444+ if c != '-' {
445+ return false
446+ }
447+ default :
448+ if ! isHex (c ) {
449+ return false
450+ }
451+ }
452+ }
453+ return true
454+ }
455+
456+ func isHex (c byte ) bool {
457+ return ('0' <= c && c <= '9' ) || ('a' <= c && c <= 'f' ) || ('A' <= c && c <= 'F' )
458+ }
0 commit comments