惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
N
News and Events Feed by Topic
PCI Perspectives
PCI Perspectives
Help Net Security
Help Net Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
V2EX - 技术
V2EX - 技术
Google Online Security Blog
Google Online Security Blog
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Palo Alto Networks Blog
The Last Watchdog
The Last Watchdog
C
Cyber Attacks, Cyber Crime and Cyber Security
Security Latest
Security Latest
Application and Cybersecurity Blog
Application and Cybersecurity Blog
W
WeLiveSecurity
Cloudbric
Cloudbric
O
OpenAI News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Webroot Blog
Webroot Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Schneier on Security
罗磊的独立博客
雷峰网
雷峰网
S
Security Affairs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LINUX DO - 热门话题
NISL@THU
NISL@THU
量子位
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 【当耐特】
博客园 - Franky
S
Security @ Cisco Blogs
Project Zero
Project Zero
AI
AI
T
Troy Hunt's Blog
Latest news
Latest news
Simon Willison's Weblog
Simon Willison's Weblog
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tailwind CSS Blog
The Cloudflare Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Scott Helme
Scott Helme
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Jina AI
Jina AI
I
Intezer
V
Visual Studio Blog
Cyberwarzone
Cyberwarzone
博客园 - 叶小钗

Ivan on Containers, Kubernetes, and Server-Side

A grounded take on agentic coding for production environments Server-Side Playgrounds Reimagined: Build, Boot, and Network Your Own Virtual Labs [not a] Kubernetes 101 - Pods, Deployments, and Services As an Attempt To Automate Age-Old Infra Patterns JavaScript or TypeScript? How To Benefit From the Dichotomy On Software Design... and Good Writing Building a Firecracker-Powered Course Platform To Learn Docker and Kubernetes How To Publish a Port of a Running Container What Actually Happens When You Publish a Container Port A Visual Guide to SSH Tunnels: Local and Remote Port Forwarding Debugging Containers Like a Pro Docker: How To Debug Distroless And Slim Containers How To Extract Container Image Filesystem Using Docker | iximiuz Labs In Pursuit of Better Container Images: Alpine, Distroless, Apko, Chisel, DockerSlim, oh my! How To Start Programming In Go: Advice For Fellow DevOps Engineers Kubernetes Ephemeral Containers and kubectl debug Command How To Develop Kubernetes CLIs Like a Pro Docker Container Commands Explained: Understand, Don't Memorize | iximiuz Labs Learning Docker with Docker - Toying With DinD For Fun And Profit How To Extend Kubernetes API - Kubernetes vs. Django The Influence of Plumbing on Programming How To Call Kubernetes API from Go - Types and Common Machinery How To Call Kubernetes API using Simple HTTP Client Kubernetes API Basics - Resources, Kinds, and Objects OpenFaaS - Run Containerized Functions On Your Own Terms Learning Containers From The Bottom Up Docker Containers vs. Kubernetes Pods - Taking a Deeper Look | iximiuz Labs Learn-by-Doing Platforms for Dev, DevOps, and SRE Folks How HTTP Keep-Alive can cause TCP race condition How to Work with Container Images Using ctr | iximiuz Labs Multiple Containers, Same Port, no Reverse Proxy... Exploring Go net/http Package - On How Not To Set Socket Options Disposable Local Development Environments with Vagrant, Docker, and Arkade DevOps, SRE, and Platform Engineering My Choice of Programming Languages Prometheus Is Not a TSDB How to learn PromQL with Prometheus Playground Prometheus Cheat Sheet - Basics (Metrics, Labels, Time Series, Scraping) Rust - Writing Parsers With nom Parser Combinator Framework pq - parse and query log files as time series Prometheus Cheat Sheet - Moving Average, Max, Min, etc (Aggregation Over Time) Prometheus Cheat Sheet - How to Join Multiple Metrics (Vector Matching) The Need For Slimmer Containers Understanding Rust Privacy and Visibility Model Bridge vs. Switch: Takeaways from a Real Data Center Tour | iximiuz Labs From LAN to VXLAN: Networking Basics for Non-Network Engineers | iximiuz Labs KiND - How I Wasted a Day Loading Local Docker Images Go, HTTP handlers, panic, and deadlocks Exploring Kubernetes Operator Pattern Making Sense Out Of Cloud Native Buzz Service Discovery in Kubernetes: Combining the Best of Two Worlds API Developers Never REST How Container Networking Works: Building a Bridge Network From Scratch | iximiuz Labs Traefik: canary deployments with weighted load balancing Service Proxy, Pod, Sidecar, oh my! You Need Containers To Build Images You Don't Need an Image To Run a Container Not Every Container Has an Operating System Inside Working with container images in Go Master Go While Learning Containers Implementing Container Runtime Shim: Interactive Containers How to use Flask with gevent (uWSGI and Gunicorn editions) My 10 Years of Programming Experience Implementing Container Runtime Shim: First Code Implementing Container Runtime Shim: runc Kubernetes Repository On Flame Dealing with process termination in Linux (with Rust examples) conman - [the] Container Manager: Inception Journey From Containerization To Orchestration And Beyond Linux PTY - How docker attach and docker exec Commands Work Inside Illustrated introduction to Linux iptables From Docker Container to Bootable Linux Disk Image Пишем свой веб-сервер на Python: протокол HTTP 9001 способ создать веб-сервер на Python Explaining async/await in 200 lines of code Explaining event loop in 100 lines of code Save the day with gevent Пишем свой веб-сервер на Python: процессы, потоки и асинхронный I/O Node.js Writable streams distilled Node.js Readable streams distilled How to on starting processes (mostly in Linux) Дайджест интересных ссылок – Июль 2016 Пишем свой веб-сервер на Python: сокеты Наследование в JavaScript Мастерить!
Truly optional scalar types in protobuf3 (with Go examples)
Ivan Velichko · 2019-04-10 · via Ivan on Containers, Kubernetes, and Server-Side

In contrast to protobuf2 there is no way in protobuf3 to mark some fields as optional and some other fields as required. Instead, any field might be omitted leading this field to be set to its default zero-value. I believe there were many good reasons for such a design decision. However, while this behavior might be superior to the proto2's explicit distinction between required and optional fields, it also has some unfortunate implications.

Gopher + protobuf = love

Level up your server-side game — join 20,000 engineers getting insightful learning materials straight to their inbox.

From proto3 Language Guide:

When a message is parsed, if the encoded message does not contain a particular singular element, the corresponding field in the parsed object is set to the default value for that field

  • For strings, the default value is the empty string.
  • For bytes, the default value is empty bytes.
  • For bools, the default value is false.
  • For numeric types, the default value is zero.
  • For enums, the default value is the first defined enum value, which must be 0.
  • For message fields, the field is not set. Its exact value is language-dependent. See the generated code guide for details.

Note that for scalar message fields, once a message is parsed there's no way of telling whether a field was explicitly set to the default value (for example whether a boolean was set to false) or just not set at all: you should bear this in mind when defining your message types. For example, don't have a boolean that switches on some behaviour when set to false if you don't want that behaviour to also happen by default. Also note that if a scalar message field is set to its default, the value will not be serialized on the wire.

Sometimes, the absence of field is not the same as the field in its default value. Or there might be no default value at all. Example:

// person.proto

syntax = "proto3";
package main;

message Person {
    int32 age = 1;  // in full years
};

Compile it:

protoc --go_out=. person.proto

Test program:

// main.go

package main
import "fmt"

func main() {
    john := Person{}
    fmt.Println(john.Age)
}

Run it:

go run person.pb.go main.go
> 0

For a kid less than a year old, a corresponding Person object will have age equal to 0. However, if a person's profile was filled only partially, we simply might not know the age of the person. But if we set the age of such person to its default value (which is 0 for numeric types), we would automatically make the person a child. While a redesigning our domain model and refactoring the age to dateOfBirth could be a better solution for this particular problem, it would be great to have a way to address such situations on the protocol level too.

So, it means that we need a strategy, how to deal with truly optional fields. Luckily, protobuf3 offers a solution - wrapper types for scalar value types from the Protocol Buffers Well-Known Types namespace. The idea is really simple. Instead of having an integer (or float, or boolean, etc.) field in the message, we use Int32Value field which is a wrapper around int32 scalar value type.

// person.proto

syntax = "proto3";
package main;

import "google/protobuf/wrappers.proto";

message Person {
    google.protobuf.Int32Value age = 2;
};

Wrappers make scalar types composite, enabling some behavior customization. Implementation for different languages may vary, but generated Go code will look as follows:

// person.bp.go

import (
    wrappers "github.com/golang/protobuf/ptypes/wrappers"
)

type Person struct {
    Age *wrappers.Int32Value `protobuf:"bytes,2,opt,name=age,proto3" json:"age,omitempty"`
    // ...
}

// ...

After construction of a Person object, we will simply have nil for the age field as it's a default zero-value for pointers in Go. But now we also can distinguish between an absence of a value for a field and its zero-value. Check the snippet:

// main.go

package main
import "fmt"
import "github.com/golang/protobuf/ptypes/wrappers"

func main() {
    john := Person{}
    fmt.Println(john.Age)

    alice := Person{Age: &wrappers.Int32Value{Value: 0}}
    fmt.Printf("%#v\n", alice.Age)
}

Run it:

go run person.pb.go main.go
> <nil>
> &wrappers.Int32Value{Value:0, ...}

Thus, if you don't know the age of a person, just skip the field. It will be set to nil and after decoding on the receiver side, the absence of the value will be noticeable. But if you have a value, even though it might be equal to the type's default value (i.e. 0), the fact that you specified it will be also transparent. And the protobuf compiler is smart enough to deal with this convention for all the supported backends. The output above shows that for Go wrappers are basically structs with the field Value of the corresponding scalar type.

Bonus: JSON interoperability

Protobuf is striving to achieve maximal interoperability between different programming languages as well as between heterogeneous systems. It provides a first class support for JSON encoding of the messages. Specifically for Go, one can notice the generated JSON annotations in the .pb.go files (see an example above). However, the default Go encoding/json package doesn't work well when it comes to wrapper types:

// main.go

package main

import "encoding/json"
import "fmt"
import "github.com/golang/protobuf/ptypes/wrappers"

func main() {
    alice := Person{Age: &wrappers.Int32Value{Value: 0}}
    bytes, _ := json.Marshal(alice)
    fmt.Println(string(bytes))

    bob := Person{Age: &wrappers.Int32Value{Value: 42}}
    bytes, _ = json.Marshal(bob)
    fmt.Println(string(bytes))
}

Run it:

go run person.pb.go main.go
> {"age":{}}
> {"age":{"value":42}}

The produced JSON above doesn't look valid since we have an object instead of an integer field. To solve this problem one needs to use jsonpb package provided by Go protocol buffer backend:

// main.go

package main

import "fmt"
import "github.com/golang/protobuf/jsonpb"
import "github.com/golang/protobuf/ptypes/wrappers"

func main() {
    alice := Person{Age: &wrappers.Int32Value{Value: 0}}
    bob := Person{Age: &wrappers.Int32Value{Value: 42}}

    m := jsonpb.Marshaler{}
    a, _ := m.MarshalToString(&alice)
    fmt.Println(a)

    b, _ := m.MarshalToString(&bob)
    fmt.Println(b)
}

Run it:

go run person.pb.go main.go
> {"age":0}
> {"age":42}

This package is aware of the wrappers purpose and can generate a valid JSON for wrapped scalar fields.

Make code not war!

Level up your server-side game — join 20,000 engineers getting insightful learning materials straight to their inbox: