Skip to content

Commit

Permalink
Add a hands on tutorial for using the operator (#172)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChunyiLyu committed Jun 23, 2021
1 parent 0a22c11 commit e56c8eb
Showing 1 changed file with 173 additions and 0 deletions.
173 changes: 173 additions & 0 deletions docs/tutorial/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Tutorial

In this tutorial, we will use the Messaging Topology Operator to create and configure:
1. a queue
1. a user
1. assign permission to the user
1. publish and consume messages to the created queue

### Prerequisites:
Your Kubernetes cluster needs to have:
1. Cluster Operator and Messaging Topology Operator installed
1. a RabbitmqCluster deployed

### Create a queue

You can create a queue by creating a custom resource `queues.rabbitmq.com`. For example:
```yaml
apiVersion: rabbitmq.com/v1beta1
kind: Queue
metadata:
name: tutorial
namespace: REPLACEME #same namespace as the deployed RabbitmqCluster
spec:
name: tutorial # this will be the name of the queue
rabbitmqClusterReference:
name: # name of the RabbitmqCluster
```

This will create a classic queue named 'tutorial' in default '/' vhost. To check the queue is created
successfully, you can ssh onto your RabbitmqCluster pod

```bash
kubectl exec -it NAME-OF-THE-RMQ-POD -- /bin/bash
```

and run the following command to see if queue 'tutorial' is listed:

```bash
rabbitmqctl list_queues
```

### Create a User

You can create a RabbitMQ user with pre-defined username and password.
Username and password are passed to the Operator through a Kubernetes secret object:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: user-secret
namespace: REPLACEME #same namespace as the deployed RabbitmqCluster
type: Opaque
stringData:
username: test
password: test
```

Then, lets create a RabbitMQ user by creating a custom resource `users.rabbitmq.com`:
```yaml
apiVersion: rabbitmq.com/v1beta1
kind: User
metadata:
name: tutorial-user
namespace: REPLACEME #same namespace as the deployed RabbitmqCluster
spec:
importCredentialsSecret:
name: user-secret
rabbitmqClusterReference:
name: # name of the RabbitmqCluster
```

This will create a RabbitMQ user with username 'test' and password 'test' (as specified in the Kubernetes secret).

### Configure Permissions

Before we can use the user 'test' to publish and consume messages, we need to grant it permissions.
This can be achieved by create a custom resource `permissions.rabbitmq.com`:
```yaml
apiVersion: rabbitmq.com/v1beta1
kind: Permission
metadata:
name: tutorial-user-permission
namespace: REPLACEME #same namespace as the deployed RabbitmqCluster
spec:
vhost: "/"
user: "test" # name of the created user
permissions:
write: ".*"
configure: ".*"
read: ".*"
rabbitmqClusterReference:
name: # name of the RabbitmqCluster
```

This is the equivalent of running `rabbitmqctl set_permissions -p "/" "test" ".*" ".*" ".*"`.

To check user 'test' is created and configured with the right permissions, you can ssh onto your
RabbitmqCluster pod, and run:
```bash
rabbitmqctl list_permissions
```
This command will list all users that has access to the default vhost '/'. You should see user 'test' listed
here with read, write, and configure permissions all set to '.*'.

### Publish and consume messages

We now have everything we need to be able to publish and consume messages. The following Golang example
uses the created user 'test' to publish and consume messages from queue 'tutorial'. The example uses the [RabbitMQ
Golang client](https://github.com/rabbitmq/amqp091-go):

```golang

package main

import (
"fmt"
"log"
amqp "github.com/rabbitmq/amqp091-go"
)

func main() {
rmqHostname := "" // please put in external ip or hostname for the deployed RabbitmqCluster
conn, err := amqp.Dial(fmt.Sprintf("amqp://test:test@%s:5672/", rmqHostname)) // username 'test' and password 'test'
if err != nil {
log.Fatalf("%s: %s", "Failed to connect to RabbitMQ", err)
}
defer conn.Close()

ch, err := conn.Channel()
if err != nil {
log.Fatalf("%s: %s", "Failed to open a channel", err)
}
defer ch.Close()

// publish message
msg := "Topology Operator Tutorial" // message body
if err = ch.Publish(
"",
"tutorial", // name of the queue as routing key
false, // mandatory
false, // immediate
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(msg),
}); err != nil {
log.Fatalf("%s: %s", "Failed to publish a message", err)
}
log.Printf("Message published: %s", msg)

//consume and print message
msgs, err := ch.Consume(
"tutorial", // name of the queue
"",
true, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
if err != nil {
log.Fatalf("%s: %s", "Failed to register a consumer", err)
}

for m := range msgs {
log.Printf("Received message: %s", m.Body)
m.Ack(false)
}
}
```

### Useful Links

Messaging Topology Operator [documentation](https://www.rabbitmq.com/kubernetes/operator/operator-overview.html#topology-operator), [API reference](https://github.com/rabbitmq/messaging-topology-operator/blob/main/docs/api/rabbitmq.com.ref.asciidoc), and [more examples](https://github.com/rabbitmq/messaging-topology-operator/tree/main/docs/examples).

0 comments on commit e56c8eb

Please sign in to comment.