Open wgnathanael opened 3 months ago
@wgnathanael , Thank you for your feedback.
Based on your comments, there appears to be a misunderstanding concerning the system behavior. As per your description, when the number of replicas is increased by one, the newly initiated pod assumes the role of a slave. However, my understanding is that the default behavior when starting Redis is for the new instance to act as a master. Only in this, the standalone master will be add to the replication topology during the "CreateMasterSlaveReplication" process.
Hello, Thanks for the quick response.
Yeah, its fine that a new Redis instance starts out as a master. The issue is once the operator controller runs, they all become slaves to nothing. So before the scale, I have 1 master and 1 slave. When I increase the number of replicas, I end up with 3 slaves, 2 of whom don't know who the master is and one that still does but the instance it connects to thinks its a replica.
Essentially, what I think the problem is is the CreateMasterSlaveReplication
process doesn't have a way of determining which of the two newest masters was the original master and reconfigures them incorrectly. I'm still investigating this but was hoping that someone here would see the behaviour and have a sense of how that code is getting it wrong.
Just after I sent the above I continued looking at the code. I think the issue is checkAttachedSlave
. Not so much the function but some other initial configuration issue. It is looking for the previous existing master. It does this by looking at all master/leader pods and finding the one with multiple connected replicas. This must be failing, and its true I remember in our output missing the connected replica output so they are setup as replicas but can't communicate with their leader. I'll continue to investigate the root cause.
In looking at the logs for the initial replica node I see the following:
9:S 21 Mar 2024 13:59:56.091 * MASTER <-> REPLICA sync started
9:S 21 Mar 2024 13:59:56.091 * Non blocking connect for SYNC fired the event.
9:S 21 Mar 2024 13:59:56.093 # Failed to read response from the server: No error information
9:S 21 Mar 2024 13:59:56.093 # Master did not respond to command during SYNC handshake
It must be having issues communicating with the leader node.
This is the issue https://github.com/OT-CONTAINER-KIT/redis/pull/75. When I add tls-replication yes
to my additional redis configuration it works. The follower can communicate with the leader.
It seems to me that however unlikely it is, it may be worthwhile in the method CreateMasterSlaveReplication
some logic that if we have multiple leaders and multiple follower pods and can't find the "realMasterPod" that we do nothing and log an error. Since this situation only happens if the replicas haven't been able to connect to a master. We can also find the real leader by querying all the followers and making sure they all point to the same "real leader"
Hey @wgnathanael! Could you kindly share the Redis replication YAMLs that include TLS configuration? I'd love to use them for reproducing purposes. Thank you so much!
Sure. The configmap:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-external-config
data:
redis-additional.conf: |
tls-replication yes
loadmodule /usr/local/lib/libOmsDriver.so /usr/local/lib/rules/
---
apiVersion: v1
kind: Secret
metadata:
name: scrs-redis-replication-tls
data:
# I've included both tls.key and peer-key.pem as it seems how the operator reads this is different,
# It seems like the TLS key in the replication manifest used to define what key to use here,
# but with the latest operator it seems it just expects tls.key/tls.crt etc.
peer-key.pem: <base64 encoded data>
peer.pem: <base64 encoded data>
root-ca.pem: <base64 encoded data>
tls.key: <base64 encoded data>
tls.crt: <base64 encoded data>
ca.crt: <base64 encoded data>
---
apiVersion: v1
kind: Secret
metadata:
name: scrs-redis-secret
data:
redisPassword: M2FiNGM4NzA=
Replication:
---
apiVersion: redis.redis.opstreelabs.in/v1beta2
kind: RedisReplication
metadata:
name: redis-replication
spec:
clusterSize: 2
TLS:
ca: root-ca.pem
cert: peer.pem
key: peer-key.pem
secret:
secretName: scrs-redis-replication-tls
redisConfig:
additionalRedisConfig: redis-external-config
kubernetesConfig:
image: registry.willowglen.ca/sq/sq-scadacom/scadacom-runtime-service/wg-redis:gnat-test-v3
imagePullPolicy: IfNotPresent
redisSecret:
name: scrs-redis-secret
key: redisPassword
storage:
volumeClaimTemplate:
spec:
# storageClassName: standard
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
podSecurityContext:
runAsUser: 1000
fsGroup: 1000
I've removed some mounts and the sidecar we include as they don't really have anything to do with the issue.
The image (which is from a private registry so you won't be able to pull it has the following Dockerfile contents
ARG BASE_BUILD_CONTAINER_VER=latest
ARG BASE_IMAGE=quay.io/opstree/redis:v7.0.12
FROM registry.willowglen.ca/sq/base-containers/base-build-container:${BASE_BUILD_CONTAINER_VER} as builder
FROM $BASE_IMAGE as base
ARG BASE_IMAGE
ARG OCI_LABEL_PREFIX=org.opencontainers
# update default values accordingly for the image
ARG LABEL_PREFIX=sq.sq-scadacom.scadacom-runtime-service.wg-redis
# passed in as build-arg, with default values if not built by gitlab
ARG IMAGE_CREATED
ARG IMAGE_VERSION
ARG IMAGE_REVISION
ARG CODE_DATE
ARG CODE_BRANCH
ARG BUILD_ENV="dev-vm"
LABEL $OCI_LABEL_PREFIX.image.created="$IMAGE_CREATED"
LABEL $OCI_LABEL_PREFIX.image.version="$IMAGE_VERSION"
LABEL $OCI_LABEL_PREFIX.image.revision="$IMAGE_REVISION"
LABEL $OCI_LABEL_PREFIX.image.base.name="$BASE_IMAGE"
LABEL $OCI_LABEL_PREFIX.image.title="Willowglen Redis"
LABEL $OCI_LABEL_PREFIX.image.description="This is the wg-redis image"
LABEL $LABEL_PREFIX.image.created="$IMAGE_CREATED"
LABEL $LABEL_PREFIX.image.url="$PROJECT_URL"
LABEL $LABEL_PREFIX.image.version="$IMAGE_VERSION"
LABEL $LABEL_PREFIX.image.revision="$IMAGE_REVISION"
LABEL $LABEL_PREFIX.image.base.name="$BASE_IMAGE"
LABEL $LABEL_PREFIX.image.code.date="$CODE_DATE"
LABEL $LABEL_PREFIX.image.code.branch="$CODE_BRANCH"
LABEL $LABEL_PREFIX.image.build-env="$BUILD_ENV"
USER root
# Install built OMS Driver redis module to expected location
RUN mkdir -p /usr/local/lib
COPY ./build/src/lib /usr/local/lib/
# Install required libraries
RUN apk add --no-cache libstdc++ gcompat
Essentially we have a base build container where things were compiled then we copy in a redis module to your image.
Let me know if you need any more information.
What version of redis operator are you using? v0.15.0 (but also latest main branch where we modified a few lines and log statements for our own instruction/understanding)
redis-operator version: v0.15.1
Does this issue reproduce with the latest release? Yes
What operating system and processor architecture are you using (
kubectl version
)? RHEL 9.2 x86_64kubectl version
OutputWhat did you do?
Starting with a simple replication.yaml taken from the example directory. Configured TLS + redisPassword and a couple of volumes. clusterSize = 2.
Allowed it to come up and the controller to assign one as leader and one as follower. Our script to check this outputs:
Then we edit the RedisReplica (though we've also tested changed the replica set that the controller has created with identical results).
The additional pod comes up, The controller notices and initiates the code to create leader/followers. Once its complete we have the following output:
The script outputting that is doing a redis-cli info replication as such:
run_redis_cmd $n "info replication" | grep -e 'role:' -e 'master_host:' -e 'slave[0-9]:'
What did you expect to see?
I would expect
What did you see instead?
All three pods are slave instead of leader as per:
Additional Details Because we changed the logging to debug this here's diff of our changes thus far.