How to Build a DingTalk ChatOps Bot with Go: A Step‑by‑Step Guide
Learn why ChatOps matters and how to create a DingTalk chatbot using Go, covering setup, security signatures, HTTP headers, and integration with CI/CD, monitoring, and Kubernetes, complete with code examples and deployment steps for streamlined operations.
What is the purpose?
Why develop ChatOps and what is it? Various Ops concepts such as DevOps, AIOps, ChatOps, NoOps all aim to intensify operational workflows, often making operations feel overwhelming. ChatOps uses chat interfaces to perform operational tasks, offering a lightweight way to automate work.
Typical application scenarios include:
Integrating with CI/CD tools like Jenkins, GitLab, GitHub to trigger builds, releases, and code merges.
Connecting with task management systems such as JIRA, Trello, Tower, ZenTao, email to handle tasks.
Working with Kubernetes platforms to create and deploy containers.
Receiving alerts from monitoring systems like Zabbix, Prometheus, Open‑Falcon.
ChatOps builds on existing tools and brings clear benefits:
Transparency: All work messages are stored in a single chat platform, visible to all members, eliminating communication barriers and preserving history.
Context sharing: Reduces message fragmentation caused by switching tools, ensuring complete information flow across roles and tools.
Mobile friendliness: Interact with backend tools via a chatbot on mobile without dealing with numerous complex interfaces.
DevOps culture promotion: Conversing with a bot lowers the entry barrier for DevOps practices, spreading automation across the team.
This article demonstrates how to use a DingTalk robot for ChatOps.
Adding a DingTalk Robot
Log in to the DingTalk developer console, navigate to Application Development > Enterprise Internal Development > Robot , and click Create Application .
Remember the AppKey and AppSecret:
Configure the server's outbound IP and message receiving URL:
Note: Configuring an HTTPS address requires a valid certificate.
Developing the Robot
HTTP HEADER
<code>{
"Content-Type": "application/json; charset=utf-8",
"timestamp": "1577262236757",
"sign": "xxxxxxxxxx"
}</code>Parameter
Description
timestamp
Message sending timestamp in milliseconds.
sign
Signature value.
Developers must verify the
timestampand
signin the header to ensure the request originates from DingTalk. Validation rules:
If the
timestampdiffers from the current system time by more than one hour, the request is considered illegal.
If the
signdoes not match the developer‑computed value, the request is illegal.
Both
timestampand
signmust pass verification. The
signis calculated by concatenating
timestamp, a newline, and the robot's
appSecret, then applying HMAC‑SHA256 and Base64 encoding.
Below is a Go implementation:
<code>package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"github.com/gin-gonic/gin"
)
const (
appSecret = "xxx-xxx"
baseHookUrl = "https://oapi.dingtalk.com/robot/send"
accessToken = "xxx"
)
type incoming struct {
MsgType string `json:"msgtype"`
Text *Text `json:"text"`
MsgId string `json:"msgId"`
CreateAt int64 `json:"createAt"`
ConversationType string `json:"conversationType"`
ConversationId string `json:"conversationId"`
ConversationTitle string `json:"conversationId"`
SenderId string `json:"senderId"`
SenderNick string `json:"senderNick"`
SenderCorpId string `json:"senderCorpId"`
SenderStaffId string `json:"senderStaffId"`
ChatbotUserId string `json:"chatbotUserId"`
AtUsers []map[string]string `json:"atUsers"`
SessionWebhook string `json:"sessionWebhook"`
IsAdmin bool `json:"isAdmin"`
}
type Message struct {
MsgType string `json:"msgtype"`
At At `json:"at,omitempty"`
Text *Text `json:"text,omitempty"`
Markdown *Markdown `json:"markdown,omitempty"`
Link *Link `json:"link,omitempty"`
}
type At struct {
AtMobiles []string `json:"atMobiles,omitempty"`
IsAtAll bool `json:"isAtAll,omitempty"`
}
type Markdown struct {
Title string `json:"title,omitempty"`
Text string `json:"text,omitempty"`
}
type Text struct {
Content string `json:"content,omitempty"`
}
type Link struct {
Title string `json:"title,omitempty"`
Text string `json:"text,omitempty"`
MessageURL string `json:"messageURL,omitempty"`
PicURL string `json:"picURL,omitempty"`
}
func main() {
r := gin.New()
r.POST("/chatops", func(c *gin.Context) {
var (
sign string
data []byte
)
httpSign := c.Request.Header.Get("Sign")
httpTimestamp := c.Request.Header.Get("Timestamp")
if tsi, err := strconv.ParseInt(httpTimestamp, 10, 64); err != nil {
fmt.Println("Request header missing timestamp!")
} else {
data, _ = ioutil.ReadAll(c.Request.Body)
sign = signature(tsi, appSecret)
}
if httpSign == sign {
var body incoming
if err := json.Unmarshal(data, &body); err != nil {
fmt.Println(err)
return
}
content := body.Text.Content
fmt.Println(content)
sendDingTalk("主人," + content)
}
})
r.Run(":9000")
}
func signature(ts int64, secret string) string {
strToSign := fmt.Sprintf("%d\n%s", ts, secret)
hmac256 := hmac.New(sha256.New, []byte(secret))
hmac256.Write([]byte(strToSign))
data := hmac256.Sum(nil)
return base64.StdEncoding.EncodeToString(data)
}
func sendDingTalk(content string) {
msg := &Message{
MsgType: "markdown",
At: At{},
Markdown: &Markdown{
Title: "消息测试",
Text: content,
},
}
query := url.Values{}
query.Set("access_token", accessToken)
hookUrl, _ := url.Parse(baseHookUrl)
hookUrl.RawQuery = query.Encode()
msgContent, _ := json.Marshal(msg)
req, err := http.NewRequest("POST", hookUrl.String(), bytes.NewReader(msgContent))
if err != nil {
fmt.Println(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
}
</code>Deploy the service to a server and test the bot in a DingTalk group. The bot will respond to messages that match configured keywords.
Note: The DingTalk robot must be configured with specific keywords; only messages containing those keywords will trigger a response.
Documentation
DingTalk Robot API Documentation
Ops Development Stories
Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.