github.com/replicatedcom/ship@v0.50.0/integration/unfork/elastic-stack/expected/rendered.yaml (about)

     1  apiVersion: v1
     2  kind: ServiceAccount
     3  metadata:
     4    labels:
     5      app: elasticsearch
     6      chart: elasticsearch-0.5.1
     7      heritage: Tiller
     8      release: elastic-stack
     9    name: elastic-stack-elasticsearch
    10  ---
    11  apiVersion: v1
    12  data:
    13    elasticsearch.yml: |-
    14      cluster.name: elasticsearch
    15  
    16      node.data: ${NODE_DATA:true}
    17      node.master: ${NODE_MASTER:true}
    18      node.ingest: ${NODE_INGEST:true}
    19      node.name: ${HOSTNAME}
    20  
    21      network.host: 0.0.0.0
    22      # see https://github.com/kubernetes/kubernetes/issues/3595
    23      bootstrap.memory_lock: ${BOOTSTRAP_MEMORY_LOCK:false}
    24  
    25      discovery:
    26        zen:
    27          ping.unicast.hosts: ${DISCOVERY_SERVICE:}
    28          minimum_master_nodes: ${MINIMUM_MASTER_NODES:2}
    29  
    30      # see https://github.com/elastic/elasticsearch-definitive-guide/pull/679
    31      processors: ${PROCESSORS:}
    32  
    33      # avoid split-brain w/ a minimum consensus of two masters plus a data node
    34      gateway.expected_master_nodes: ${EXPECTED_MASTER_NODES:2}
    35      gateway.expected_data_nodes: ${EXPECTED_DATA_NODES:1}
    36      gateway.recover_after_time: ${RECOVER_AFTER_TIME:5m}
    37      gateway.recover_after_master_nodes: ${RECOVER_AFTER_MASTER_NODES:2}
    38      gateway.recover_after_data_nodes: ${RECOVER_AFTER_DATA_NODES:1}
    39  
    40      # Extra Configuration
    41  
    42      # X-Pack
    43  
    44      # Search Guard
    45    log4j2.properties: |-
    46      status = error
    47  
    48      appender.console.type = Console
    49      appender.console.name = console
    50      appender.console.layout.type = PatternLayout
    51      appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n
    52  
    53      rootLogger.level = info
    54      rootLogger.appenderRef.console.ref = console
    55    pre-stop-hook.sh: |-
    56      #!/bin/bash
    57      set -e
    58  
    59      SERVICE_ACCOUNT_PATH=/var/run/secrets/kubernetes.io/serviceaccount
    60      KUBE_TOKEN=$(<${SERVICE_ACCOUNT_PATH}/token)
    61      KUBE_NAMESPACE=$(<${SERVICE_ACCOUNT_PATH}/namespace)
    62  
    63      STATEFULSET_NAME=$(echo "${HOSTNAME}" | sed 's/-[0-9]*$//g')
    64      INSTANCE_ID=$(echo "${HOSTNAME}" | grep -o '[0-9]*$')
    65  
    66      echo "Prepare stopping of Pet ${KUBE_NAMESPACE}/${HOSTNAME} of StatefulSet ${KUBE_NAMESPACE}/${STATEFULSET_NAME} instance_id ${INSTANCE_ID}"
    67  
    68      export STATEFULSET_STATUS=$(
    69        curl -s \
    70          --cacert ${SERVICE_ACCOUNT_PATH}/ca.crt \
    71          -H "Authorization: Bearer $KUBE_TOKEN" \
    72          "https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_PORT_443_TCP_PORT}/apis/apps/v1beta1/namespaces/${KUBE_NAMESPACE}/statefulsets/${STATEFULSET_NAME}/status"
    73      )
    74      INSTANCES_DESIRED=$(
    75      	python - <<-EOF
    76      		import json
    77      		import os
    78  
    79      		obj = json.loads(os.environ.get('STATEFULSET_STATUS'))
    80      		print(obj['spec']['replicas'])
    81      	EOF
    82      )
    83  
    84      echo "Desired instance count is ${INSTANCES_DESIRED}"
    85  
    86      if [ "${INSTANCE_ID}" -lt "${INSTANCES_DESIRED}" ]; then
    87        echo "No data migration needed"
    88        exit 0
    89      fi
    90  
    91      echo "Prepare to migrate data of the node"
    92  
    93      export NODE_STATS=$(
    94        curl -X GET -s \
    95          http://127.0.0.1:9200/_nodes/stats
    96      )
    97      NODE_IP=$(
    98      	python - <<-EOF
    99      		import json
   100      		import os
   101  
   102      		obj = json.loads(os.environ.get('NODE_STATS'))
   103      		key = list(filter(lambda datum: obj['nodes'][datum]['name'] == os.environ.get('HOSTNAME'), obj['nodes'].keys()))[0]
   104      		node = obj['nodes'][key]
   105      		print(node['host'])
   106      	EOF
   107      )
   108  
   109      echo "Move all data from node ${NODE_IP}"
   110  
   111      curl -X PUT -H "Content-Type: application/json" -s \
   112        http://127.0.0.1:9200/_cluster/settings \
   113        --data "{
   114            \"transient\" :{
   115                \"cluster.routing.allocation.exclude._ip\" : \"${NODE_IP}\"
   116            }
   117          }"
   118      echo
   119  
   120      echo "Wait for node documents to become empty"
   121      DOC_COUNT=$(
   122      	python - <<-EOF
   123      		import json
   124      		import os
   125  
   126      		obj = json.loads(os.environ.get('NODE_STATS'))
   127      		key = list(filter(lambda datum: obj['nodes'][datum]['name'] == os.environ.get('HOSTNAME'), obj['nodes'].keys()))[0]
   128      		node = obj['nodes'][key]
   129      		print(node['indices']['docs']['count'])
   130      	EOF
   131      )
   132  
   133      while [ "${DOC_COUNT}" -gt 0 ]; do
   134        export NODE_STATS=$(
   135          curl -X GET -s \
   136            http://127.0.0.1:9200/_nodes/stats
   137        )
   138        DOC_COUNT=$(
   139      		python - <<-EOF
   140      			import json
   141      			import os
   142  
   143      			obj = json.loads(os.environ.get('NODE_STATS'))
   144      			key = list(filter(lambda datum: obj['nodes'][datum]['name'] == os.environ.get('HOSTNAME'), obj['nodes'].keys()))[0]
   145      			node = obj['nodes'][key]
   146      			count = node['indices']['docs']['count']
   147      			print(count)
   148      		EOF
   149        )
   150        echo "Node contains ${DOC_COUNT} documents"
   151        sleep 1
   152      done
   153  
   154      echo "Wait for node shards to become empty"
   155      export SHARD_STATS=$(
   156        curl -X GET -s \
   157          http://127.0.0.1:9200/_cat/shards?format=json
   158      )
   159      SHARD_COUNT=$(
   160      	python - <<-EOF
   161      		import json
   162      		import os
   163  
   164      		obj = json.loads(os.environ.get('SHARD_STATS'))
   165      		count = len(filter(lambda datum: datum['node'] == os.environ.get('HOSTNAME'), obj))
   166      		print(count)
   167      	EOF
   168      )
   169      while [ "${SHARD_COUNT}" -gt 0 ]; do
   170        export SHARD_STATS=$(
   171          curl -X GET -s \
   172            http://127.0.0.1:9200/_cat/shards?format=json
   173        )
   174        SHARD_COUNT=$(
   175      		python - <<-EOF
   176      			import json
   177      			import os
   178  
   179      			obj = json.loads(os.environ.get('SHARD_STATS'))
   180      			count = len(filter(lambda datum: datum['node'] == os.environ.get('HOSTNAME'), obj))
   181      			print(count)
   182      		EOF
   183        )
   184        echo "Node contains ${SHARD_COUNT} shards"
   185        sleep 1
   186      done
   187  
   188      echo "Node clear to shutdown"
   189  kind: ConfigMap
   190  metadata:
   191    labels:
   192      app: elastic-stack-elasticsearch
   193      chart: elasticsearch-1.16.0
   194      heritage: Tiller
   195      release: elastic-stack
   196    name: elastic-stack-elasticsearch
   197  ---
   198  apiVersion: v1
   199  kind: Service
   200  metadata:
   201    labels:
   202      app: elasticsearch
   203      chart: elasticsearch-1.16.0
   204      component: client
   205      heritage: Tiller
   206      release: elastic-stack
   207    name: elastic-stack-elasticsearch-client
   208  spec:
   209    ports:
   210    - port: 9200
   211      targetPort: http
   212    selector:
   213      app: elasticsearch
   214      component: client
   215      release: elastic-stack
   216    type: ClusterIP
   217  ---
   218  apiVersion: v1
   219  kind: Service
   220  metadata:
   221    labels:
   222      app: elasticsearch
   223      chart: elasticsearch-0.5.1
   224      component: master
   225      heritage: Tiller
   226      release: elastic-stack
   227    name: elastic-stack-elasticsearch-master
   228  spec:
   229    clusterIP: None
   230    ports:
   231    - port: 9300
   232      targetPort: 9300
   233    selector:
   234      app: elasticsearch
   235      component: master
   236      release: elastic-stack
   237  ---
   238  apiVersion: v1
   239  kind: Service
   240  metadata:
   241    labels:
   242      app: kibana
   243      chart: kibana-1.1.2
   244      heritage: Tiller
   245      release: elastic-stack
   246    name: elastic-stack-kibana
   247  spec:
   248    ports:
   249    - name: kibana
   250      port: 80
   251      protocol: TCP
   252      targetPort: 5601
   253    selector:
   254      app: kibana
   255      release: elastic-stack
   256    type: ClusterIP
   257  ---
   258  apiVersion: apps/v1beta1
   259  kind: Deployment
   260  metadata:
   261    labels:
   262      app: elasticsearch
   263      chart: elasticsearch-1.16.0
   264      component: client
   265      heritage: Tiller
   266      release: elastic-stack
   267    name: elastic-stack-elasticsearch-client
   268  spec:
   269    replicas: 2
   270    template:
   271      metadata:
   272        annotations:
   273          checksum/config: 4f07b9e19327171c37a9c353906c75a1f454cd31c3dfc600a8882d6e36713c49
   274          checksum/secret: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
   275        labels:
   276          app: elasticsearch
   277          component: client
   278          release: elastic-stack
   279      spec:
   280        affinity:
   281          podAntiAffinity:
   282            preferredDuringSchedulingIgnoredDuringExecution:
   283            - podAffinityTerm:
   284                labelSelector:
   285                  matchLabels:
   286                    app: elasticsearch
   287                    component: client
   288                    release: elastic-stack
   289                topologyKey: kubernetes.io/hostname
   290              weight: 1
   291        containers:
   292        - env:
   293          - name: DISCOVERY_SERVICE
   294            value: elastic-stack-elasticsearch-master.default.svc.cluster.local
   295          - name: NODE_DATA
   296            value: "false"
   297          - name: NODE_INGEST
   298            value: "false"
   299          - name: ES_HEAP_SIZE
   300            value: 512m
   301          - name: NODE_MASTER
   302            value: "false"
   303          - name: PROCESSORS
   304            valueFrom:
   305              resourceFieldRef:
   306                resource: limits.cpu
   307          - name: ES_JAVA_OPTS
   308            value: -Djava.net.preferIPv4Stack=true
   309          - name: MINIMUM_MASTER_NODES
   310            value: "2"
   311          image: gcr.io/cos-containers/elasticsearch:5.4.2-xpack
   312          imagePullPolicy: Always
   313          livenessProbe:
   314            exec:
   315              command:
   316              - sh
   317              - -c
   318              - curl --request GET --silent --output /dev/null http://127.0.0.1:9200/_cluster/health?wait_for_status=yellow
   319            initialDelaySeconds: 90
   320          name: elasticsearch
   321          ports:
   322          - containerPort: 9200
   323            name: http
   324          - containerPort: 9300
   325            name: transport
   326          readinessProbe:
   327            exec:
   328              command:
   329              - sh
   330              - -c
   331              - curl --request GET --silent --output /dev/null http://127.0.0.1:9200/_cluster/health?wait_for_status=yellow
   332            initialDelaySeconds: 5
   333          resources:
   334            limits:
   335              cpu: "1"
   336            requests:
   337              cpu: 25m
   338              memory: 512Mi
   339          volumeMounts:
   340          - mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
   341            name: config
   342            readOnly: true
   343            subPath: elasticsearch.yml
   344          - mountPath: /usr/share/elasticsearch/config/log4j2.properties
   345            name: config
   346            readOnly: true
   347            subPath: log4j2.properties
   348        initContainers:
   349        - command:
   350          - sh
   351          - -c
   352          - |-
   353            # see https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html
   354            # and https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration-memory.html#mlockall
   355            # and https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-cli-run-prod-mode
   356            sysctl -w vm.max_map_count=262144
   357            # To increase the ulimit
   358            # https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_notes_for_production_use_and_defaults
   359            ulimit -l unlimited
   360          image: busybox
   361          name: increase-memory-limits
   362          securityContext:
   363            privileged: true
   364        securityContext:
   365          fsGroup: 1000
   366        serviceAccountName: elastic-stack-elasticsearch
   367        volumes:
   368        - configMap:
   369            name: elastic-stack-elasticsearch
   370          name: config
   371  ---
   372  apiVersion: apps/v1beta1
   373  kind: Deployment
   374  metadata:
   375    labels:
   376      app: kibana
   377      chart: kibana-1.1.2
   378      heritage: Tiller
   379      release: elastic-stack
   380    name: elastic-stack-kibana
   381  spec:
   382    replicas: 1
   383    template:
   384      metadata:
   385        labels:
   386          app: kibana
   387          release: elastic-stack
   388      spec:
   389        containers:
   390        - env:
   391          - name: XPACK_MONITORING_ENABLED
   392            value: "true"
   393          - name: ELASTICSEARCH_URL
   394            value: http://elastic-stack-elasticsearch:9200
   395          image: docker.elastic.co/kibana/kibana:5.4.2
   396          imagePullPolicy: IfNotPresent
   397          livenessProbe:
   398            httpGet:
   399              path: /
   400              port: 5601
   401            initialDelaySeconds: 180
   402          name: kibana
   403          ports:
   404          - containerPort: 5601
   405            name: http
   406          readinessProbe:
   407            httpGet:
   408              path: /status
   409              port: 5601
   410            initialDelaySeconds: 180
   411            periodSeconds: 10
   412          securityContext:
   413            runAsNonRoot: true
   414            runAsUser: 1000
   415  ---
   416  apiVersion: apps/v1beta1
   417  kind: StatefulSet
   418  metadata:
   419    labels:
   420      app: elasticsearch
   421      chart: elasticsearch-1.16.0
   422      component: data
   423      heritage: Tiller
   424      release: elastic-stack
   425    name: elastic-stack-elasticsearch-data
   426  spec:
   427    replicas: 2
   428    serviceName: elastic-stack-elasticsearch-data
   429    template:
   430      metadata:
   431        annotations:
   432          checksum/config: 4f07b9e19327171c37a9c353906c75a1f454cd31c3dfc600a8882d6e36713c49
   433          checksum/secret: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
   434        labels:
   435          app: elasticsearch
   436          component: data
   437          release: elastic-stack
   438      spec:
   439        affinity:
   440          podAntiAffinity:
   441            preferredDuringSchedulingIgnoredDuringExecution:
   442            - podAffinityTerm:
   443                labelSelector:
   444                  matchLabels:
   445                    app: elasticsearch
   446                    component: data
   447                    release: elastic-stack
   448                topologyKey: kubernetes.io/hostname
   449              weight: 1
   450        containers:
   451        - env:
   452          - name: DISCOVERY_SERVICE
   453            value: elastic-stack-elasticsearch-master.default.svc.cluster.local
   454          - name: NODE_MASTER
   455            value: "false"
   456          - name: PROCESSORS
   457            valueFrom:
   458              resourceFieldRef:
   459                resource: limits.cpu
   460          - name: ES_HEAP_SIZE
   461            value: 1536m
   462          - name: ES_JAVA_OPTS
   463            value: -Djava.net.preferIPv4Stack=true
   464          - name: MINIMUM_MASTER_NODES
   465            value: "2"
   466          image: gcr.io/cos-containers/elasticsearch:5.4.2-xpack
   467          imagePullPolicy: Always
   468          lifecycle:
   469            preStop:
   470              exec:
   471                command:
   472                - /bin/bash
   473                - /pre-stop-hook.sh
   474          name: elasticsearch
   475          ports:
   476          - containerPort: 9300
   477            name: transport
   478          readinessProbe:
   479            exec:
   480              command:
   481              - sh
   482              - -c
   483              - curl --request GET --silent --output /dev/null http://127.0.0.1:9200/_cluster/health?local=true
   484            initialDelaySeconds: 5
   485          resources:
   486            limits:
   487              cpu: "1"
   488            requests:
   489              cpu: 25m
   490              memory: 1536Mi
   491          volumeMounts:
   492          - mountPath: /usr/share/elasticsearch/data
   493            name: data
   494          - mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
   495            name: config
   496            readOnly: true
   497            subPath: elasticsearch.yml
   498          - mountPath: /usr/share/elasticsearch/config/log4j2.properties
   499            name: config
   500            readOnly: true
   501            subPath: log4j2.properties
   502          - mountPath: /pre-stop-hook.sh
   503            name: config
   504            subPath: pre-stop-hook.sh
   505        initContainers:
   506        - command:
   507          - sh
   508          - -c
   509          - |-
   510            # see https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html
   511            # and https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration-memory.html#mlockall
   512            # and https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-cli-run-prod-mode
   513            sysctl -w vm.max_map_count=262144
   514            # To increase the ulimit
   515            # https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_notes_for_production_use_and_defaults
   516            ulimit -l unlimited
   517          image: busybox
   518          name: increase-memory-limits
   519          securityContext:
   520            privileged: true
   521        securityContext:
   522          fsGroup: 1000
   523        serviceAccountName: elastic-stack-elasticsearch
   524        terminationGracePeriodSeconds: 3600
   525        volumes:
   526        - configMap:
   527            name: elastic-stack-elasticsearch
   528          name: config
   529    volumeClaimTemplates:
   530    - metadata:
   531        name: data
   532      spec:
   533        accessModes:
   534        - ReadWriteOnce
   535        resources:
   536          requests:
   537            storage: 4Gi
   538  ---
   539  apiVersion: apps/v1beta1
   540  kind: StatefulSet
   541  metadata:
   542    labels:
   543      app: elasticsearch
   544      chart: elasticsearch-1.16.0
   545      component: master
   546      heritage: Tiller
   547      release: elastic-stack
   548    name: elastic-stack-elasticsearch-master
   549  spec:
   550    replicas: 2
   551    serviceName: elastic-stack-elasticsearch-master
   552    template:
   553      metadata:
   554        annotations:
   555          checksum/config: 4f07b9e19327171c37a9c353906c75a1f454cd31c3dfc600a8882d6e36713c49
   556          checksum/secret: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
   557        labels:
   558          app: elasticsearch
   559          component: master
   560          release: elastic-stack
   561      spec:
   562        affinity:
   563          podAntiAffinity:
   564            preferredDuringSchedulingIgnoredDuringExecution:
   565            - podAffinityTerm:
   566                labelSelector:
   567                  matchLabels:
   568                    app: elasticsearch
   569                    component: master
   570                    release: elastic-stack
   571                topologyKey: kubernetes.io/hostname
   572              weight: 1
   573        containers:
   574        - env:
   575          - name: DISCOVERY_SERVICE
   576            value: elastic-stack-elasticsearch-master.default.svc.cluster.local
   577          - name: NODE_DATA
   578            value: "false"
   579          - name: NODE_INGEST
   580            value: "false"
   581          - name: ES_HEAP_SIZE
   582            value: 512m
   583          - name: PROCESSORS
   584            valueFrom:
   585              resourceFieldRef:
   586                resource: limits.cpu
   587          - name: ES_JAVA_OPTS
   588            value: -Djava.net.preferIPv4Stack=true
   589          - name: MINIMUM_MASTER_NODES
   590            value: "2"
   591          image: gcr.io/cos-containers/elasticsearch:5.4.2-xpack
   592          imagePullPolicy: Always
   593          name: elasticsearch
   594          ports:
   595          - containerPort: 9300
   596            name: transport
   597          readinessProbe:
   598            exec:
   599              command:
   600              - sh
   601              - -c
   602              - curl --request GET --silent --output /dev/null http://127.0.0.1:9200/_cluster/health?local=true
   603            initialDelaySeconds: 5
   604          resources:
   605            limits:
   606              cpu: "1"
   607            requests:
   608              cpu: 25m
   609              memory: 512Mi
   610          volumeMounts:
   611          - mountPath: /usr/share/elasticsearch/data
   612            name: data
   613          - mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
   614            name: config
   615            readOnly: true
   616            subPath: elasticsearch.yml
   617          - mountPath: /usr/share/elasticsearch/config/log4j2.properties
   618            name: config
   619            readOnly: true
   620            subPath: log4j2.properties
   621        initContainers:
   622        - command:
   623          - sh
   624          - -c
   625          - |-
   626            # see https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html
   627            # and https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration-memory.html#mlockall
   628            # and https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-cli-run-prod-mode
   629            sysctl -w vm.max_map_count=262144
   630            # To increase the ulimit
   631            # https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_notes_for_production_use_and_defaults
   632            ulimit -l unlimited
   633          image: busybox
   634          name: increase-memory-limits
   635          securityContext:
   636            privileged: true
   637        securityContext:
   638          fsGroup: 1000
   639        serviceAccountName: elastic-stack-elasticsearch
   640        volumes:
   641        - configMap:
   642            name: elastic-stack-elasticsearch
   643          name: config
   644    volumeClaimTemplates:
   645    - metadata:
   646        name: data
   647      spec:
   648        accessModes:
   649        - ReadWriteOnce
   650        resources:
   651          requests:
   652            storage: 4Gi
   653  ---
   654  apiVersion: policy/v1beta1
   655  kind: PodDisruptionBudget
   656  metadata:
   657    labels:
   658      app: elasticsearch
   659      chart: elasticsearch-0.5.1
   660      component: client
   661      heritage: Tiller
   662      release: elastic-stack
   663    name: elastic-stack-elasticsearch-client
   664  spec:
   665    maxUnavailable: 1
   666    selector:
   667      matchLabels:
   668        app: elasticsearch
   669        component: client
   670        release: elastic-stack
   671  ---
   672  apiVersion: policy/v1beta1
   673  kind: PodDisruptionBudget
   674  metadata:
   675    labels:
   676      app: elasticsearch
   677      chart: elasticsearch-0.5.1
   678      component: data
   679      heritage: Tiller
   680      release: elastic-stack
   681    name: elastic-stack-elasticsearch-data
   682  spec:
   683    maxUnavailable: 1
   684    selector:
   685      matchLabels:
   686        app: elasticsearch
   687        component: data
   688        release: elastic-stack
   689  ---
   690  apiVersion: policy/v1beta1
   691  kind: PodDisruptionBudget
   692  metadata:
   693    labels:
   694      app: elasticsearch
   695      chart: elasticsearch-0.5.1
   696      component: master
   697      heritage: Tiller
   698      release: elastic-stack
   699    name: elastic-stack-elasticsearch-master
   700  spec:
   701    maxUnavailable: 1
   702    selector:
   703      matchLabels:
   704        app: elasticsearch
   705        component: master
   706        release: elastic-stack