[ Agent ] [ Status ] - refresh status part

This commit is contained in:
zeaslity
2023-12-20 15:50:08 +08:00
parent 3312052645
commit 4d56083b5a
15 changed files with 423 additions and 68 deletions

View File

@@ -794,6 +794,14 @@ func (op *AgentOsOperator) deployIngress(funcArgs []string) (bool, []string) {
result = append(result, "替换SUPREME信息") result = append(result, "替换SUPREME信息")
return false, result return false, result
} }
parseIP = net.ParseIP(funcArgs[3])
if parseIP == nil {
return false, append(result, "ip args error !")
}
if !BasicReplace(k8sIngressYamlFile, "A1C1IP", funcArgs[3]) {
result = append(result, "替换A1C1IP信息")
return false, result
}
if !BasicReplace(k8sIngressYamlFile, "A1C1JS", funcArgs[4]) { if !BasicReplace(k8sIngressYamlFile, "A1C1JS", funcArgs[4]) {
result = append(result, "替换A1C1JS信息") result = append(result, "替换A1C1JS信息")
return false, result return false, result

View File

@@ -167,14 +167,19 @@ func statusOMHandler(octopusMessage *OctopusMessage) {
return return
} }
// OMessageStatusTypeEnum
var statusRes string var statusRes string
if strings.HasPrefix(statusMessage.StatusType, "P") { if strings.HasPrefix(statusMessage.StatusType, "PING") {
// ping info // ping info
statusRes = status.Ping() statusRes = status.Ping()
} else { } else if strings.HasPrefix(statusMessage.StatusType, "METRIC") {
// metric info // metric info
agentStatusString, _ := json.Marshal(status.ReportAppStatus()) agentStatusString, _ := json.Marshal(status.ReportAppStatus())
statusRes = string(agentStatusString) statusRes = string(agentStatusString)
} else if strings.HasPrefix(statusMessage.StatusType, "INFO") {
} else {
log.WarnF("[statusOMHandler] - error octopus status message type of %s", statusMessage.StatusType)
} }
// 返回消息 // 返回消息

View File

@@ -3,28 +3,29 @@ package status
import ( import (
"github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/load" "github.com/shirou/gopsutil/v3/load"
"time"
) )
type CPUStatus struct { type CPUMetric struct {
NumCores int NumCores int
CPUInfo []cpu.InfoStat CPUPercent float64
CPUPercent float64 CPULoads *load.AvgStat
CPULoads *load.AvgStat
SystemLoads *load.AvgStat
} }
func GetCPUStatus() (*CPUStatus, error) { type CPUInfo struct {
CPUMetric
CPUInfo []cpu.InfoStat
}
func GetCPUMetric() (*CPUMetric, error) {
numCores, err := cpu.Counts(true) numCores, err := cpu.Counts(true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
cpuInfo, err := cpu.Info() cpuPercent, err := cpu.Percent(time.Second, false)
if err != nil {
return nil, err
}
cpuPercent, err := cpu.Percent(0, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -34,17 +35,42 @@ func GetCPUStatus() (*CPUStatus, error) {
return nil, err return nil, err
} }
systemLoads, err := load.Avg() return &CPUMetric{
NumCores: numCores,
CPUPercent: cpuPercent[0],
CPULoads: cpuLoads,
}, nil
}
func GetCPUInfo() (*CPUInfo, error) {
numCores, err := cpu.Counts(true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &CPUStatus{ cpuPercent, err := cpu.Percent(time.Second, false)
NumCores: numCores, if err != nil {
CPUInfo: cpuInfo, return nil, err
CPUPercent: cpuPercent[0], }
CPULoads: cpuLoads,
SystemLoads: systemLoads, cpuLoads, err := load.Avg()
if err != nil {
return nil, err
}
infoStats, err := cpu.Info()
if err != nil {
return nil, err
}
return &CPUInfo{
CPUMetric: CPUMetric{
NumCores: numCores,
CPUPercent: cpuPercent[0],
CPULoads: cpuLoads,
},
CPUInfo: infoStats,
}, nil }, nil
} }

View File

@@ -7,7 +7,7 @@ import (
) )
func TestGetCPUStatus(t *testing.T) { func TestGetCPUStatus(t *testing.T) {
cpuStatus, err := GetCPUStatus() cpuStatus, err := GetCPUMetric()
if err != nil { if err != nil {
return return
} }
@@ -20,3 +20,17 @@ func TestGetCPUStatus(t *testing.T) {
fmt.Println(string(marshalIndent)) fmt.Println(string(marshalIndent))
} }
func TestGetCPUInfo(t *testing.T) {
cpuInfo, err := GetCPUInfo()
if err != nil {
return
}
marshalIndent, err := json.MarshalIndent(cpuInfo, "", " ")
if err != nil {
fmt.Printf("error")
}
fmt.Println(string(marshalIndent))
}

View File

@@ -10,7 +10,6 @@ func TestGetDiskStatus(t *testing.T) {
ds := GetDiskStatus() ds := GetDiskStatus()
fmt.Printf("Total: %v, Used: %v\n", ds.Total, ds.Used) fmt.Printf("Total: %v, Used: %v\n", ds.Total, ds.Used)
fmt.Printf("Logical Disks: %v\n", ds.LogicalDisk)
marshalIndent, err := json.MarshalIndent(ds, "", " ") marshalIndent, err := json.MarshalIndent(ds, "", " ")
if err != nil { if err != nil {

22
agent-go/status/Host.go Normal file
View File

@@ -0,0 +1,22 @@
package status
import (
"github.com/shirou/gopsutil/v3/host"
)
type HostInfo struct {
host.InfoStat
}
func GetHostInfo() (*HostInfo, error) {
info, err := host.Info()
if err != nil {
log.ErrorF("get host info error => %v", err)
return nil, err
}
return &HostInfo{
InfoStat: *info,
}, nil
}

View File

@@ -0,0 +1,25 @@
package status
import (
"fmt"
"testing"
)
func TestGetHostInfo(t *testing.T) {
hostInfo := HostInfo{}
fmt.Printf("host info is %v\n", hostInfo)
fmt.Printf("host info type is %T\n", hostInfo)
fmt.Printf("host info address is %p\n", &hostInfo)
fmt.Println()
info, err := GetHostInfo()
if err != nil {
t.Errorf("get host info error is %v", err)
}
fmt.Printf("get host info is %v\n", info)
fmt.Printf("get host info address is %p\n", &info)
}

View File

@@ -5,29 +5,106 @@ import (
"github.com/shirou/gopsutil/v3/mem" "github.com/shirou/gopsutil/v3/mem"
) )
type MemoryStatus struct { type MemoryMetric struct {
TotalMemory uint64 TotalMemory uint64
UsedMemory uint64 AvailableMemory uint64
AvailableMemory uint64 UsedMemory uint64
TotalVirtualMemory uint64 UsedPercent float64 `json:"usedPercent"`
UsedVirtualMemory uint64 FreeMemory uint64 `json:"free"`
} }
func GetMemoryStatus() (*MemoryStatus, error) { type MemoryInfo struct {
memoryStatus := &MemoryStatus{} MemoryMetric
Buffers uint64 `json:"buffers"`
Cached uint64 `json:"cached"`
WriteBack uint64 `json:"writeBack"`
Dirty uint64 `json:"dirty"`
WriteBackTmp uint64 `json:"writeBackTmp"`
Shared uint64 `json:"shared"`
Slab uint64 `json:"slab"`
Sreclaimable uint64 `json:"sreclaimable"`
Sunreclaim uint64 `json:"sunreclaim"`
PageTables uint64 `json:"pageTables"`
SwapCached uint64 `json:"swapCached"`
CommitLimit uint64 `json:"commitLimit"`
CommittedAS uint64 `json:"committedAS"`
HighTotal uint64 `json:"highTotal"`
HighFree uint64 `json:"highFree"`
LowTotal uint64 `json:"lowTotal"`
LowFree uint64 `json:"lowFree"`
SwapTotal uint64 `json:"swapTotal"`
SwapFree uint64 `json:"swapFree"`
Mapped uint64 `json:"mapped"`
VmallocTotal uint64 `json:"vmallocTotal"`
VmallocUsed uint64 `json:"vmallocUsed"`
VmallocChunk uint64 `json:"vmallocChunk"`
HugePagesTotal uint64 `json:"hugePagesTotal"`
HugePagesFree uint64 `json:"hugePagesFree"`
HugePagesRsvd uint64 `json:"hugePagesRsvd"`
HugePagesSurp uint64 `json:"hugePagesSurp"`
HugePageSize uint64 `json:"hugePageSize"`
}
func GetMemoryStatus() (*MemoryMetric, error) {
virtualMemoryStat, err := mem.VirtualMemory()
if err != nil {
return nil, err
}
return &MemoryMetric{
TotalMemory: virtualMemoryStat.Total,
AvailableMemory: virtualMemoryStat.Available,
UsedMemory: virtualMemoryStat.Used,
UsedPercent: virtualMemoryStat.UsedPercent,
FreeMemory: virtualMemoryStat.Free,
}, nil
}
func GetMemoryInfo() (*MemoryInfo, error) {
virtualMemoryStat, err := mem.VirtualMemory() virtualMemoryStat, err := mem.VirtualMemory()
if err != nil { if err != nil {
return memoryStatus, err return nil, err
} }
memoryStatus.TotalMemory = virtualMemoryStat.Total return &MemoryInfo{
memoryStatus.UsedMemory = virtualMemoryStat.Used MemoryMetric: MemoryMetric{
memoryStatus.AvailableMemory = virtualMemoryStat.Available TotalMemory: virtualMemoryStat.Total,
memoryStatus.TotalVirtualMemory = virtualMemoryStat.Total AvailableMemory: virtualMemoryStat.Available,
memoryStatus.UsedVirtualMemory = virtualMemoryStat.Used UsedMemory: virtualMemoryStat.Used,
UsedPercent: virtualMemoryStat.UsedPercent,
return memoryStatus, nil FreeMemory: virtualMemoryStat.Free,
},
Buffers: virtualMemoryStat.Buffers,
Cached: virtualMemoryStat.Cached,
WriteBack: virtualMemoryStat.WriteBack,
Dirty: virtualMemoryStat.Dirty,
WriteBackTmp: virtualMemoryStat.WriteBackTmp,
Shared: virtualMemoryStat.Shared,
Slab: virtualMemoryStat.Slab,
Sreclaimable: virtualMemoryStat.Sreclaimable,
Sunreclaim: virtualMemoryStat.Sunreclaim,
PageTables: virtualMemoryStat.PageTables,
SwapCached: virtualMemoryStat.SwapCached,
CommitLimit: virtualMemoryStat.CommitLimit,
CommittedAS: virtualMemoryStat.CommittedAS,
HighTotal: virtualMemoryStat.HighTotal,
HighFree: virtualMemoryStat.HighFree,
LowTotal: virtualMemoryStat.LowTotal,
LowFree: virtualMemoryStat.LowFree,
SwapTotal: virtualMemoryStat.SwapTotal,
SwapFree: virtualMemoryStat.SwapFree,
Mapped: virtualMemoryStat.Mapped,
VmallocTotal: virtualMemoryStat.VmallocTotal,
VmallocUsed: virtualMemoryStat.VmallocUsed,
VmallocChunk: virtualMemoryStat.VmallocChunk,
HugePagesTotal: virtualMemoryStat.HugePagesTotal,
HugePagesFree: virtualMemoryStat.HugePagesFree,
HugePagesRsvd: virtualMemoryStat.HugePagesRsvd,
HugePagesSurp: virtualMemoryStat.HugePagesSurp,
HugePageSize: virtualMemoryStat.HugePageSize,
}, nil
} }
func FormatMemorySize(size uint64) string { func FormatMemorySize(size uint64) string {

View File

@@ -14,10 +14,31 @@ func TestGetMemoryStatus(t *testing.T) {
} }
fmt.Printf("Total Memory: %s\n", FormatMemorySize(memoryStatus.TotalMemory)) fmt.Printf("Total Memory: %s\n", FormatMemorySize(memoryStatus.TotalMemory))
fmt.Printf("Used Memory: %s\n", FormatMemorySize(memoryStatus.UsedMemory))
fmt.Printf("Available Memory: %s\n", FormatMemorySize(memoryStatus.AvailableMemory)) fmt.Printf("Available Memory: %s\n", FormatMemorySize(memoryStatus.AvailableMemory))
fmt.Printf("Total Virtual Memory: %s\n", FormatMemorySize(memoryStatus.TotalVirtualMemory)) fmt.Printf("Used Memory: %s\n ", FormatMemorySize(memoryStatus.UsedMemory))
fmt.Printf("Used Virtual Memory: %s\n", FormatMemorySize(memoryStatus.UsedVirtualMemory)) fmt.Printf("UsedPercent: %.2f %%\n", memoryStatus.UsedPercent)
fmt.Printf("Free Memory: %s\n", FormatMemorySize(memoryStatus.FreeMemory))
marshalIndent, err := json.MarshalIndent(memoryStatus, "", " ")
if err != nil {
fmt.Printf("error")
}
fmt.Println(string(marshalIndent))
}
func TestGetMemoryInfo(t *testing.T) {
memoryStatus, err := GetMemoryInfo()
if err != nil {
return
}
fmt.Printf("Total Memory: %s\n", FormatMemorySize(memoryStatus.TotalMemory))
fmt.Printf("Used Memory: %s\n", FormatMemorySize(memoryStatus.UsedMemory))
fmt.Printf("Available Memory: %s\n", FormatMemorySize(memoryStatus.AvailableMemory))
fmt.Printf("UsedPercent: %.2f %%\n", memoryStatus.UsedPercent)
fmt.Printf("Free Memory: %s\n", FormatMemorySize(memoryStatus.FreeMemory))
marshalIndent, err := json.MarshalIndent(memoryStatus, "", " ") marshalIndent, err := json.MarshalIndent(memoryStatus, "", " ")
if err != nil { if err != nil {

View File

@@ -2,12 +2,21 @@ package status
import ( import (
"fmt" "fmt"
"github.com/go-openapi/errors"
"github.com/shirou/gopsutil/v3/net" "github.com/shirou/gopsutil/v3/net"
net2 "net" net2 "net"
"regexp"
"strings" "strings"
"time" "time"
) )
type NetworkMetric struct {
net.IOCountersStat
SendSpeed float64
RecvSpeed float64
}
type NetworkStatus struct { type NetworkStatus struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
InternalIPv4 []string `json:"internal_ip_v4,omitempty"` InternalIPv4 []string `json:"internal_ip_v4,omitempty"`
@@ -21,6 +30,73 @@ type NetworkStatus struct {
RecvRate string `json:"recv_rate,omitempty"` RecvRate string `json:"recv_rate,omitempty"`
} }
func GetNetworkMetric() ([]NetworkMetric, error) {
interfaceStatList, err := net.Interfaces()
if err != nil {
log.ErrorF("[GetNetworkMetric] - get interface list error %v\n", err)
return nil, err
}
contains := false
for _, interfaceStat := range interfaceStatList {
if MatchNetInterfaceRight(interfaceStat.Name) {
contains = true
break
}
}
if !contains {
msg := "[GetNetworkMetric]- can not find desired net interface !"
log.Warn(msg)
return nil, errors.New(233, msg)
}
ioCountersStats, err := net.IOCounters(false)
if err != nil {
log.ErrorF("[GetNetworkMetric] - get io counter list error %v\n", err)
return nil, err
}
duration := time.Second * 2
time.Sleep(duration)
afterIoCounterList, err := net.IOCounters(false)
if err != nil {
log.ErrorF("[GetNetworkMetric] - get io counter list second error %v\n", err)
return nil, err
}
var result []NetworkMetric
for _, interfaceStat := range interfaceStatList {
if MatchNetInterfaceRight(interfaceStat.Name) {
for _, after := range afterIoCounterList {
if strings.Contains(after.Name, interfaceStat.Name) {
for _, before := range ioCountersStats {
if strings.Contains(before.Name, interfaceStat.Name) {
// match after and before interface
// assign
networkMetric := NetworkMetric{
IOCountersStat: after,
SendSpeed: 0,
RecvSpeed: 0,
}
networkMetric.SendSpeed = (float64(after.BytesSent - before.BytesSent)) / duration.Seconds()
networkMetric.RecvSpeed = (float64(after.BytesRecv - before.BytesRecv)) / duration.Seconds()
result = append(result, networkMetric)
}
}
}
}
}
}
return result, nil
}
func GetNetworkStatus() (*NetworkStatus, error) { func GetNetworkStatus() (*NetworkStatus, error) {
interfaces, err := net.Interfaces() interfaces, err := net.Interfaces()
if err != nil { if err != nil {
@@ -119,3 +195,18 @@ func GetInternelIpAddrs(addresses []string) ([]string, []string) {
} }
return ipv4, ipv6 return ipv4, ipv6
} }
func MatchNetInterfaceRight(interfaceName string) bool {
match, _ := regexp.MatchString(`^(eth|enp|wlan|ens|eno)\d+`, interfaceName)
if match {
return true
}
match, _ = regexp.MatchString(`^(lo)`, interfaceName)
if match {
return true
}
return match
}

View File

@@ -20,3 +20,27 @@ func TestGetNetworkInfo(t *testing.T) {
fmt.Println(string(marshalIndent)) fmt.Println(string(marshalIndent))
} }
func TestMatchNetInterfaceRight(t *testing.T) {
interfaceNames := []string{"eth0", "eth1", "enp3s0", "wlan0", "lo", "ens12", "eno1", "asdas", "en0"}
for _, name := range interfaceNames {
if MatchNetInterfaceRight(name) {
t.Logf("匹配到的网卡名称: %s\n", name)
}
}
}
func TestGetNetworkMetric(t *testing.T) {
metric, err := GetNetworkMetric()
if err != nil {
t.Logf("get network metric error %s\n", err.Error())
}
for _, networkMetric := range metric {
fmt.Println()
bytes, _ := json.MarshalIndent(networkMetric, "", " ")
fmt.Println(string(bytes))
fmt.Println()
}
}

View File

@@ -21,8 +21,8 @@ type StatusMessage struct {
} }
type AgentStatus struct { type AgentStatus struct {
CPUStatus *CPUStatus CPUStatus *CPUMetric
MemoryStatus *MemoryStatus MemoryStatus *MemoryMetric
NetworkStatus *NetworkStatus NetworkStatus *NetworkStatus
DiskStatus *DiskStatus DiskStatus *DiskStatus
} }
@@ -43,10 +43,9 @@ func Ping() string {
return "PONG" return "PONG"
} }
// todo change to go model
func ReportAppStatus() *AgentStatus { func ReportAppStatus() *AgentStatus {
cpuStatus, cpuerr := GetCPUStatus() cpuStatus, cpuerr := GetCPUMetric()
memoryStatus, memerr := GetMemoryStatus() memoryStatus, memerr := GetMemoryStatus()
networkStatus, neterr := GetNetworkStatus() networkStatus, neterr := GetNetworkStatus()
if cpuerr != nil || memerr != nil || neterr != nil { if cpuerr != nil || memerr != nil || neterr != nil {

View File

@@ -24,7 +24,7 @@ public class AppFuncScheduler {
/** /**
* 参数固定顺序为 A1C2IP SUPREME N1C2IP A1C1IP A1C1JS M2D2IP KIMMY JACLOVE * 参数固定顺序为 A1C2IP SUPREME N1C2IP A1C1IP A1C1JS M2D2IP KIMMY JACLOVE
* 1 2 3 4 5 6 7 8 * 1 2 3 4 5 6 7 8
* *
* @param projectDeployContext * @param projectDeployContext
* @param projectInfoPO * @param projectInfoPO
@@ -34,20 +34,20 @@ public class AppFuncScheduler {
ArrayList<String> appFuncArgs = new ArrayList<>(); ArrayList<String> appFuncArgs = new ArrayList<>();
appFuncArgs.add(projectDeployContext appFuncArgs.add(projectDeployContext
.getMasterNode() .getMasterNode()
.getServerIpInV4()); .getServerIpInV4());
appFuncArgs.add(projectInfoPO.getProjectNamespace()); appFuncArgs.add(projectInfoPO.getProjectNamespace());
appFuncArgs.add(projectDeployContext appFuncArgs.add(projectDeployContext
.getMasterNode() .getMasterNode()
.getServerIpInV4()); .getServerIpInV4());
appFuncArgs.add(projectDeployContext appFuncArgs.add(projectDeployContext
.getMasterNode() .getMasterNode()
.getServerIpPbV4()); .getServerIpPbV4());
appFuncArgs.add(projectInfoPO.getProjectWebServicePort()); appFuncArgs.add(projectInfoPO.getProjectWebServicePort());
// M2D2IP // M2D2IP
appFuncArgs.add(projectDeployContext appFuncArgs.add(projectDeployContext
.getMasterNode() .getMasterNode()
.getServerIpInV4()); .getServerIpInV4());
appFuncArgs.add(projectInfoPO.getProjectVersion()); appFuncArgs.add(projectInfoPO.getProjectVersion());
// jackeyLoveFile // jackeyLoveFile
appFuncArgs.add("init_5.1.0.tar"); appFuncArgs.add("init_5.1.0.tar");
@@ -106,9 +106,10 @@ public class AppFuncScheduler {
AppFunctionEnum.DEPLOY_NFS, AppFunctionEnum.DEPLOY_NFS,
AppFunctionEnum.DEPLOY_TEST_NFS, AppFunctionEnum.DEPLOY_TEST_NFS,
AppFunctionEnum.DEPLOY_K8S_NAMESPACE, AppFunctionEnum.DEPLOY_K8S_NAMESPACE,
AppFunctionEnum.DEPLOY_K8S_PVC,
AppFunctionEnum.DEPLOY_K8S_MYSQL, AppFunctionEnum.DEPLOY_K8S_MYSQL,
AppFunctionEnum.DEPLOY_K8S_REDIS, AppFunctionEnum.DEPLOY_K8S_REDIS,
AppFunctionEnum.DEPLOY_K8S_PVC, AppFunctionEnum.DEPLOY_K8S_MIDDLEWARES,
AppFunctionEnum.DEPLOY_INGRESS AppFunctionEnum.DEPLOY_INGRESS
// AppFunctionEnum.DEPLOY_FRONTEND // AppFunctionEnum.DEPLOY_FRONTEND
// AppFunctionEnum.DEPLOY_BACKEND // AppFunctionEnum.DEPLOY_BACKEND

View File

@@ -0,0 +1,28 @@
package io.wdd.rpc.status.beans;
public enum OMessageStatusTypeEnum {
PING("PING", "检测Agent主机的将抗状况"),
METRIC("METRIC", "检测Agent主机的Metric信息"),
INFO("INFO", "检测Agent主机的详细硬件信息");
String statusTypeName;
String statusDesc;
OMessageStatusTypeEnum(String statusTypeName, String statusDesc) {
this.statusTypeName = statusTypeName;
this.statusDesc = statusDesc;
}
public String getStatusTypeName() {
return statusTypeName;
}
public String getStatusDesc() {
return statusDesc;
}
}

View File

@@ -47,22 +47,37 @@ services:
volumes: volumes:
- 'rabbitmq_data:/bitnami/rabbitmq/mnesia' - 'rabbitmq_data:/bitnami/rabbitmq/mnesia'
redis: redis:
# https://hub.docker.com/r/bitnami/redis image: redis/redis-stack:6.2.6-v10
image: bitnami/redis:6.2.11-debian-11-r1
networks: networks:
- app-tier - app-tier
environment:
- REDIS_PASSWORD=boge8tingH
# Redis 6.0 features a new multi-threading model
- REDIS_IO_THREADS=4
- REDIS_IO_THREADS_DO_READS=yes
- REDIS_PORT_NUMBER=6379
- REDIS_REPLICATION_MODE=master
#- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
ports: ports:
- '21370:6379' - '21370:6379'
- '21371:8001'
environment:
# duration of 7 days
- REDISTIMESERIES_ARGS=DUPLICATE_POLICY LAST RETENTION_POLICY 604800000
# Redis 6.0 features a new multi-threading model
#- REDIS_ARGS=protected-mode no masterauth boge8tingH appendonly yes
#- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
volumes: volumes:
- 'redis_data:/bitnami/redis/data' - 'redis_data:/data'
# redis:
# # https://hub.docker.com/r/bitnami/redis
# image: bitnami/redis:6.2.11-debian-11-r1
# networks:
# - app-tier
# environment:
# - REDIS_PASSWORD=boge8tingH
# # Redis 6.0 features a new multi-threading model
# - REDIS_IO_THREADS=4
# - REDIS_IO_THREADS_DO_READS=yes
# - REDIS_PORT_NUMBER=6379
# - REDIS_REPLICATION_MODE=master
# #- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
# ports:
# - '21370:6379'
# volumes:
# - 'redis_data:/bitnami/redis/data'
volumes: volumes:
mysql_data: mysql_data: