CQ's Notes

Keep Learning, Keep Growing

Migrating from Jenkins to GitHub Actions: A Decision Framework and Comparison

This is the fourth and final article in the “Unified CI/CD Pipeline Governance” series. The first three articles covered why unified management matters, how to implement it with Jenkins, and how to implement it with GitHub Actions. The purpose of this article is to help you make an informed decision: whether to migrate, and if so, how. This article draws from a production environment covering 500+ repositories with over two years of operation — the migration decision is not theoretical, but a real set of tradeoffs that actually played out.


Read more »

GitHub Actions Reusable Workflow: A Complete Implementation of Zero-Config Unified CI/CD

This is the third post in the “Unified CI/CD Pipeline Governance” series. This article provides an in-depth breakdown of how a platform team uses Reusable Workflows to achieve “zero-config onboarding for business repositories” — covering architecture design, JWT/OIDC authentication, multi-environment routing, container builds, and lessons learned. This article draws from a real-world deployment covering 500+ repositories in production.


Read more »

Jenkins Shared Library: Engineering a Unified Pipeline

This is the second post in the “Unified CI/CD Pipeline Governance” series. The first post covered why centralized management matters; this post dives into the technical implementation details of Jenkins Shared Library. The content comes from a production system covering 500+ repositories that has been running for over two years.


Read more »

Why Centralize CI/CD Pipeline Management: The Real Cost of Fragmentation and the Value of Governance

When your organization has 500 repositories each maintaining their own CI/CD configuration, the question is not “should we centralize?” but “how long can you afford the cost of fragmentation?” This post is a practical summary from a unified CI/CD platform that has been running in production across 500+ repositories for over two years.


Read more »

In a previous post, “Unified Authentication and Authorization for Homelab Applications Using Azure AD,” we discussed in detail how to use Azure AD for centralized authentication. In “Jenkins Integration with Azure AD,” we covered how a self-hosted Jenkins instance can integrate with Azure AD.

In this post, I will walk through how to integrate Tencent Cloud with Azure AD.

Read more »

My Homelab runs many services — NAS, Jenkins, Gitlab, SonarQube, Grafana, and more. Managing authentication and authorization independently for each application creates several problems:

  • Multiple passwords to maintain.
  • If a periodic password rotation policy is enforced, that means rotating passwords across multiple applications on a regular basis.
  • Adding a new user to the Homelab environment requires creating accounts in each application separately, which is tedious.
  • When a user’s role changes, the change must be applied across every application.

My solution is: Azure AD + Windows Server AD.

Read more »

In the root directory of a code project, you will often find a README.md. What is a README? It is the project’s self-introduction — much like a resume, its purpose is to sell itself: to get a company to hire you, or to get others to adopt your project.

In this post, I will try to introduce how to write a good README.

Read more »

Version control records every change in software — every release, every bug. It runs through the entire lifecycle of software, from birth to death. Please treat every commit with care, and write your commit messages as if you were recording history.

Git is currently the most popular version control system and a great choice. As a competent software developer, you should be proficient in using it. You can construct practice scenarios to work through git commands, such as:

Read more »

A straightforward guide to using WSL. This post won’t cover what WSL is or how to install it — it simply shares how I use WSL for day-to-day development.

My current WSL configuration is as follows:

1
2
NAME            STATE           VERSION
* Ubuntu-20.04 Running 2

I rely heavily on CLI tools to boost my productivity and improve my overall experience, so a great terminal and a set of efficient CLI tools are essential for me.

Read more »

Why I Wanted to Build This App

Back in 2021, when I was revamping my desk setup, I wanted to add a clock. After looking around, I ended up getting an AWTRIX Pro mini.

There are plenty of interesting apps in the AWTRIX App Store — things like GithubFollowers, Bilibili, and so on. I installed GithubFollowers, but after a while I noticed the number was stuck at 7. Pretty embarrassing, honestly. It barely registered emotionally, so I uninstalled it.

That got me thinking — what if I could see the total view count of my blog (the sum of views across all posts)?

Read more »

2021 was a year of tremendous change for me. The overall trajectory was positive — I saw more possibilities and more hope than before.

Paid off my loan.

Changed jobs. Left ThoughtWorks and joined SAP.

Delivered my first fully English-language tech session (October 28, 2021).

Learned how to swim.

Gave my desk setup a complete makeover.

Got vaccinated against COVID-19. This was my first vaccination since elementary school. After my childhood vaccination I came down with meningitis not long after — no causal link, but the memory still made me nervous.

Bought a robot vacuum cleaner.

Built a desktop PC. Assembled it in June, only for Intel to launch its 12th-generation CPUs by year end — felt like arriving at the party just as it ends.

Got a new NAS. Total storage should now exceed 30 TB.

……

Read more »

In a continuous delivery workflow, it is often necessary to require manual confirmation before proceeding with a production deployment. This post walks through how to implement that, including a pitfall I ran into along the way.

Read more »

In pipeline best practices, dynamic pipelines are generally discouraged. Readability is crucial for any codebase, and once you start using dynamic pipelines it becomes difficult — sometimes impossible — to guarantee readability or maintainability.

That said, there are certain scenarios where dynamic pipelines can actually help you maintain or even improve readability while also improving maintainability. In those cases, using a dynamic pipeline is the right call.

Read more »

On June 2, 2021, I was released from quarantine and finally allowed out. After half a year away, I was back in my little home base.

At that point, it was clear that my next job would allow long-term work from home (WFH), so I decided the desk setup needed an overhaul — something I’d be happy living and working at every day, a setup that would truly please me.

Read more »

TL;DR

The general idea is to use the Synology package Active Backup for Business to back up VMware vSphere virtual machines in a Homelab environment.


Data disaster recovery is important — much like wearing a seatbelt when driving or a helmet when riding a motorcycle, it’s all about safety. In this post, we’ll walk through how to use a Synology NAS to back up virtual machines in vSphere.

Read more »

What is DevOps? Different organizations give different answers, and there is no single universally agreed-upon definition. To summarize:

DevOps is a combination of cultural philosophies, practices, and tools. Its goals are:

  1. To enable organizations to deliver software at high speed and with high reliability.
  2. To improve communication and collaboration within the organization. Agile software development practices broke down the “wall” between BAs (business analysts), QA (testers), and Devs (developers), enabling shared understanding of requirements. DevOps goes further by breaking down the “wall” between Dev (development) and Ops (operations), creating a continuous flow from software development through deployment to maintenance.
Read more »

I’ve been meaning to write something like this for a long time to share my simple home network setup, but I kept putting it off. Now (2021-06-20 03:20:00), I’m having a bit of insomnia, so I’m making a start — no idea when I’ll finish, we’ll see. By the time I got further into it (June 21, 2021, 22:00), the topic had drifted anyway, so I decided to just rename this post to “My Experience with Xiaomi Smart Home.”

Read more »

This is another one of my opinionated rants. Over two years working in DevOps, I’ve seen both good and bad practices. Everyone has a different understanding of DevOps, and in this post I’m simply sharing my own perspective — please feel free to correct me where I’m wrong.

Broadly speaking, I follow three principles:

  1. Zero manual operations.
  2. Keep it clean: the Boy Scout Rule.
  3. Keep it simple: Occam’s Razor.
Read more »

Every application running in production was originally developed on a software engineer’s laptop. That means every engineer has a local development environment — used for the IDE and for running tests locally.

Read more »

CI/CD is a methodology for continuous software development that minimizes the chance of introducing errors during the software development process through automation scripts. It reduces — or even eliminates — manual intervention from the development of a new feature all the way through its deployment to production.

CI/CD encompasses three concepts: Continuous Integration, Continuous Delivery, and Continuous Deployment.

Read more »

Using Node Exporter + Prometheus + Grafana to add monitoring to the Asus AX86U. There are two reasons for setting this up: first, to understand how Prometheus works; second, to try monitoring the network devices at home.

Read more »

When we want to understand something more deeply, it helps to trace its origins and evolution. This post is a brief overview of the history of DevOps.

Read more »

Pinned note: Writing this post does not mean I enjoy using Terraform.

This section is a bit verbose — feel free to skip straight to my GitHub.
Deploy with local Terraform: https://github.com/chengqing-su/lambda-deployment-via-terraform
Deploy with Docker: https://github.com/chengqing-su/lambda-deployment-via-dockerized-terraform

Read more »

2020, six years.
2021, seven years.

2020, almost all my goals fell flat.
2021, keep it simple — just stay healthy and keep going.

2020, I didn’t finish writing 100 technical blog posts; I only completed 27. By the end, I genuinely didn’t know what else to write about.
2021, aim for 52 blog posts (ideally adapted into WeChat public account articles as well), not limited to technical topics — let’s try to actually finish this time.

2020, my certification plans were also put on hold.
2021, we’ll see how time allows, but I should still try to squeeze in some free certification opportunities — why not take them when they’re there.

2020, I didn’t finish a single social science book.
2021, I must finish reading “Chinese Village”.

2020, didn’t watch many films — just “Tenet” (not that impressive), “Jiang Ziya” (fell a bit short of expectations), and “My People, My Homeland” (honestly went just to see the bit about Northeast University).
2021, hope to catch a movie in Singapore.

2020, TV series I watched: “Raised by Wolves”, “Ratched”, “The Qin Empire: Alliance” (waited so, so long for this one).
2021, whatever comes, comes.

2020, still loving web novels, still a fan of Zhai Zhu — you can feel him growing with every story. Also a fan of Bu Qiang; his work has real quality and gets the blood pumping. Finished “Eagle Falcon”, and I’ve read several of his other novels before — unfortunately, due to publishing restrictions, legitimate copies are nearly impossible to find now.
2021, keep following “Lin Yuan Xing” and “Handsome Instructor”.

2020, became a paid member on Bilibili and followed Guan Shipin. Ma Ni (the Dushan County documentary), Shen Yi (I always remember how, on his birthday, he hugged his wife stone-faced in front of everyone and just went for it), Wen Tiejun (genuinely teared up watching him talk about the Three Worlds), the Political Commissar who always toasts first, Teacher Ban Fo, and others.
2021, keep learning on Bilibili.

2020, from Xi’an to Chengdu, then from Chengdu to Singapore.
2021, hope to smoothly return to the motherland.

2021, keep grinding, fellow workers!!!

In our current project, we use a microservices architecture where backend services rely on Gradle for dependency management. When issues occur in production, we need to quickly identify which version is causing the problem. Since we don’t have application monitoring in place and our services are deployed to a Kubernetes cluster, we want a simple command to retrieve the application name, application version, and the image version in use.

Read more »

Previously, when setting up a Kubernetes cluster on vSphere, all nodes were cloned from a single CentOS template. This meant every node shared the same password — which is not particularly secure. So I decided to disable password-based SSH login across all nodes.

Read more »

Manually upgrading a cluster every time is always a pain — mindlessly repeating the same steps over and over serves no purpose. So I decided to script the upgrade process.

Before sharing my scripts, let me describe my cluster setup:

  • 3 master nodes + 3 worker nodes
  • Each node is created from the same VM template, all running CentOS.
  • Each node is accessed via ssh key pair login
Read more »

In some situations, we need to call HTTP APIs provided by third parties to retrieve specific information. In Laravel, we can use curl to make these HTTP API calls. During development and testing, however, we cannot call the real API — it may be a paid service — so we need to mock those API calls.

Although this post focuses on how to mock curl, the same approach can be extended to mocking any built-in PHP function. Below is a simple example that we will use as the subject of our mock tests.

Read more »

This post originally started as an exploration of the difference between * and @ in shell arrays. But as I wrote it, I realized the issue I had encountered wasn’t actually about * vs @ — it was a subtle problem with the way I was removing elements from an array. In this post, I’ll walk through how to delete an element from a shell array.

Read more »

ConfigMap is used to store non-sensitive information as key-value pairs. Pods can consume ConfigMaps via environment variables, command-line arguments, or volume mounts.
ConfigMap decouples environment-specific configuration from your application code, which improves application portability.
Note that ConfigMap does not provide any encryption.

Read more »

A Deployment Pipeline (pipeline for short) is a series of steps for applying code changes to a production environment. It describes the CI/CD process and relies on a CI/CD platform (such as Jenkins, GitLab CI/CD, Buildkite, GOCD, etc.). Through a pipeline, code changes are deployed to any environment within minutes or tens of minutes via a fully automated, scripted process.

Read more »

A PersistentVolumeClaim (PVC) is a request for storage by a user. It is similar to a Pod. Pods consume Node resources, and PVCs consume PV resources. Pods can request specific levels of resources (CPU and memory). PVCs can request PVs with a specific size and access mode (for example, they can be mounted as read/write once or read-only many times).

Read more »

A PersistentVolume (PV) is a piece of storage in a Kubernetes cluster, provisioned by an administrator or dynamically provisioned using a Storage Class. Its lifecycle is independent of any individual Pod that uses it.

Read more »

Most of us own multiple mobile devices and run into common problems: too many passwords to remember, weak passwords that are insecure, lost files when a device goes missing, and the hassle of working across devices.
In this post I will walk through how I manage my passwords, as well as how I handle file syncing and backup. Everything here is aimed at personal, non-commercial use.

Read more »

Previously, I was creating Kubernetes clusters on Rancher manually. Since I frequently create and delete clusters for testing purposes, doing this by hand every time gets tedious quickly.
In this post, I’ll walk through creating a Rancher cluster and the follow-up steps needed afterward.

Read more »

When a container crashes, kubelet will attempt to restart it, but any files that existed in the container before will be lost. In addition, sharing files between multiple containers within a Pod is often necessary. Kubernetes provides a Volume abstraction to address these problems.

Read more »

Before implementing continuous integration, one critical prerequisite is automated builds.

An automated build must satisfy one condition: both humans and computers can automatically execute the application’s build, test, and deployment process via the command line. Automation scripts are the embodiment of turning automated builds into scripted form.

This post introduces some principles and practices for writing automation scripts.

Read more »

Service is a core concept in Kubernetes. By creating a Service, you can provide a unified entry point for a group of container applications that share the same function, and distribute incoming requests to the individual container applications on the backend.

Read more »

A Job creates one or more Pods and ensures that those Pods terminate successfully.

A simple scenario: create a Job to guarantee that a Pod runs to completion reliably. If the first Pod fails or is deleted before finishing, the Job will start a new Pod.

Read more »

A DaemonSet ensures that all (or some) nodes run a copy of a Pod. The word “Daemon” in computing refers to a background process.

When a new node is added to the cluster, the DaemonSet creates a new Pod on that node. When a node is removed from the cluster, those Pods are garbage collected. Deleting a DaemonSet will clean up all the Pods it created.

Read more »

StatefulSet is an object used to manage stateful applications. A StatefulSet manages the deployment and scaling of a set of Pods, and guarantees the ordering and uniqueness of those Pods.

Like a Deployment, a StatefulSet manages Pods that are based on an identical container spec. Unlike a Deployment, a StatefulSet maintains a sticky identity for each of its Pods. These Pods are created from the same spec, but are not interchangeable — each has a persistent identifier that is maintained across any rescheduling.

Read more »

A Deployment provides declarative updates for Pods and ReplicaSets (in simple terms, it lets you use kubectl apply to update the Pod configuration managed by a ReplicaSet).

Read more »

In Kubernetes, a controller is a control loop (in robotics and automation, a control loop is a non-terminating loop that regulates the state of a system) that watches the state of a cluster and makes or requests changes when needed. Each controller tries to move the current cluster state closer to the desired state.

A ReplicaSet is one of Kubernetes’ controllers. At any given time, a ReplicaSet maintains a stable set of replica Pods. It is typically used to guarantee the availability of a specified number of identical Pods.

ReplicaSets are the successors to ReplicationControllers. Both serve the same purpose and behave similarly. The difference is that ReplicationControllers do not support set-based selectors. For this reason, ReplicaSets are preferred over ReplicationControllers.

Read more »

Periodic diagnostics performed by kubelet on containers. To perform a diagnostic, kubelet calls a Handler implemented by the container.

Read more »

Init Containers are specialized containers that run before application containers start in a Pod.

A Pod can have multiple init containers.

Read more »

The kubelet accepts a set of PodSpecs provided through various mechanisms (primarily via the apiserver) and ensures that the containers described in those PodSpecs are running in a healthy state.

This post covers container states in Kubernetes, Pod phases, and the relationship between the two.

Read more »

What is a Pod? The word “Pod” refers to a seed pod — a very fitting name. Inside a pod, there are usually one or more seeds, just like the containers running inside a Kubernetes Pod.

Read more »

Rolling update deployment is managed by Amazon ECS. The service scheduler replaces the currently running version of a container with the specified version (which can be a newer or older version).

During a rolling update, the number of tasks Amazon ECS adds to or removes from a service is controlled by the DeploymentConfiguration.

The DeploymentConfiguration consists of the minimum and maximum number of tasks allowed to run during a service deployment.

Read more »

2019 — hit the 5-year milestone with my partner. Made a trip back to my hometown, visited Lanzhou, and climbed Mount Hua (took cable cars up and down, but walked all five peaks).
2020 — keep the momentum going. Check off all three northeastern provinces of China.

2019 — watched 12 movies in the theater. I actually sat through the mindless Shazam!. The rest: The Wandering Earth, Pegasus, Detective Pu Songling, Alita: Battle Angel, Captain Marvel, Avengers: Endgame, Men in Black: International, Spider-Man: Far From Home, Better Days, Ne Zha, and The Climbers.
2020 — no idea how many I’ll catch; I’ll go whenever something’s worth seeing.

Read more »
0%