Minio 入门 (2)

上一节我们创建了一个bucket , 不过你是否注意到一个细节, 我们使用的是http

实际项目中你往往需要通过 https 

这里将https设置为true

lizhedeMacBook-Pro:~ lizhe$ cat ~/.s3cfg

# Setup endpoint

host_base = localhost:9090

host_bucket = localhost:9090

bucket_location = us-east-1

use_https = True

 

# Setup access keys

access_key = admin

secret_key = admin123456

 

# Enable S3 v4 signature APIs

signature_v2 = False

lizhedeMacBook-Pro:~ lizhe$ 

再尝试创建发现得到了错误

lizhedeMacBook-Pro:~ lizhe$ s3cmd mb s3://mybuckethttps

ERROR: SSL certificate verification failure: [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:590)

lizhedeMacBook-Pro:~ lizhe$ 

这里要让 minio 支持 https , 需要先生成本地证书, 这里我们简单一点, 使用go

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

// Generate a self-signed X.509 certificate for a TLS server. Outputs to
// 'cert.pem' and 'key.pem' and will overwrite existing files.

package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"flag"
	"fmt"
	"log"
	"math/big"
	"net"
	"os"
	"strings"
	"time"
)

var (
	host       = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for")
	validFrom  = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
	validFor   = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
	isCA       = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
	rsaBits    = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set")
	ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521")
)

func publicKey(priv interface{}) interface{} {
	switch k := priv.(type) {
	case *rsa.PrivateKey:
		return &k.PublicKey
	case *ecdsa.PrivateKey:
		return &k.PublicKey
	default:
		return nil
	}
}

func pemBlockForKey(priv interface{}) *pem.Block {
	switch k := priv.(type) {
	case *rsa.PrivateKey:
		return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
	case *ecdsa.PrivateKey:
		b, err := x509.MarshalECPrivateKey(k)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err)
			os.Exit(2)
		}
		return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	default:
		return nil
	}
}

func main() {
	flag.Parse()

	if len(*host) == 0 {
		log.Fatalf("Missing required --host parameter")
	}

	var priv interface{}
	var err error
	switch *ecdsaCurve {
	case "":
		priv, err = rsa.GenerateKey(rand.Reader, *rsaBits)
	case "P224":
		priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
	case "P256":
		priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	case "P384":
		priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
	case "P521":
		priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
	default:
		fmt.Fprintf(os.Stderr, "Unrecognized elliptic curve: %q", *ecdsaCurve)
		os.Exit(1)
	}
	if err != nil {
		log.Fatalf("failed to generate private key: %s", err)
	}

	var notBefore time.Time
	if len(*validFrom) == 0 {
		notBefore = time.Now()
	} else {
		notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to parse creation date: %s\n", err)
			os.Exit(1)
		}
	}

	notAfter := notBefore.Add(*validFor)

	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
	if err != nil {
		log.Fatalf("failed to generate serial number: %s", err)
	}

	template := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			Organization: []string{"Acme Co"},
		},
		NotBefore: notBefore,
		NotAfter:  notAfter,

		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
	}

	hosts := strings.Split(*host, ",")
	for _, h := range hosts {
		if ip := net.ParseIP(h); ip != nil {
			template.IPAddresses = append(template.IPAddresses, ip)
		} else {
			template.DNSNames = append(template.DNSNames, h)
		}
	}

	if *isCA {
		template.IsCA = true
		template.KeyUsage |= x509.KeyUsageCertSign
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
	if err != nil {
		log.Fatalf("Failed to create certificate: %s", err)
	}

	certOut, err := os.Create("cert.pem")
	if err != nil {
		log.Fatalf("failed to open cert.pem for writing: %s", err)
	}
	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
		log.Fatalf("failed to write data to cert.pem: %s", err)
	}
	if err := certOut.Close(); err != nil {
		log.Fatalf("error closing cert.pem: %s", err)
	}
	log.Print("wrote cert.pem\n")

	keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		log.Print("failed to open key.pem for writing:", err)
		return
	}
	if err := pem.Encode(keyOut, pemBlockForKey(priv)); err != nil {
		log.Fatalf("failed to write data to key.pem: %s", err)
	}
	if err := keyOut.Close(); err != nil {
		log.Fatalf("error closing key.pem: %s", err)
	}
	log.Print("wrote key.pem\n")
}

这里 cert.pem 是公钥, key.pem是私钥, minio 只支持 pem 格式

为了让minio服务器可以打开https服务, 需要将证书放在

~/.minio/certs

当然你可以选择直接mount路径到 docker 容器, 也可以选择拷贝, 这里我使用 拷贝 的方案

lizhedeMacBook-Pro:ca lizhe$ pwd

/Users/lizhe/Documents/DEV/projects/golang/ca

lizhedeMacBook-Pro:ca lizhe$ 

lizhedeMacBook-Pro:ca lizhe$ go run generate_cert.go -ca --host "localhost"

2019/03/11 16:49:57 wrote cert.pem

2019/03/11 16:49:57 wrote key.pem

lizhedeMacBook-Pro:ca lizhe$ 

lizhedeMacBook-Pro:ca lizhe$ cp key.pem private.key

lizhedeMacBook-Pro:ca lizhe$ cp cert.pem public.crt

lizhedeMacBook-Pro:ca lizhe$ 

lizhedeMacBook-Pro:ca lizhe$ ls

cert.pem generate_cert.go key.pem private.key public.crt

lizhedeMacBook-Pro:ca lizhe$ 

lizhedeMacBook-Pro:ca lizhe$ docker run -p 9090:9000 --name studyminio -d -e MINIO_ACCESS_KEY=admin -e MINIO_SECRET_KEY=admin123456 minio/minio server /data

394e06ba0e040693919c6b568342fbf1f54b2c5fb51288a845b1116a11d70ef3

lizhedeMacBook-Pro:ca lizhe$ docker ps

CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                           PORTS                    NAMES

394e06ba0e04        minio/minio           "/usr/bin/docker-ent…"   2 seconds ago       Up 1 second (health: starting)   0.0.0.0:9090->9000/tcp   studyminio

68cafdfd8d42        portainer/portainer   "/portainer"             3 weeks ago         Up 5 hours                       0.0.0.0:9000->9000/tcp   portainer

lizhedeMacBook-Pro:ca lizhe$ 

lizhedeMacBook-Pro:ca lizhe$ docker cp private.key 394e06ba0e04:/root/.minio/certs

lizhedeMacBook-Pro:ca lizhe$ docker cp public.crt 394e06ba0e04:/root/.minio/certs

lizhedeMacBook-Pro:ca lizhe$ 

lizhedeMacBook-Pro:ca lizhe$ docker restart studyminio

studyminio

lizhedeMacBook-Pro:ca lizhe$ 

NOTE: Location of custom certs directory can be specified using --certs-dir command line option.

然后就可以通过 https://localhost:9090/ 来访问 minio 服务器了

当然 s3cmd 也可以使用了

lizhedeMacBook-Pro:ca lizhe$ cd /Users/lizhe/Documents/DEV/projects/golang/ca

lizhedeMacBook-Pro:ca lizhe$ ls

cert.pem generate_cert.go key.pem private.key public.crt

lizhedeMacBook-Pro:ca lizhe$ cat ~/.s3cfg

# Setup endpoint

host_base = localhost:9090

host_bucket = localhost:9090

bucket_location = us-east-1

use_https = True

 

# Setup access keys

access_key = admin

secret_key = admin123456

 

# Enable S3 v4 signature APIs

signature_v2 = False

lizhedeMacBook-Pro:ca lizhe$ s3cmd mb --no-check-certificate s3://mybucket1

Bucket 's3://mybucket1/' created

lizhedeMacBook-Pro:ca lizhe$ s3cmd mb --ca-certs ./public.crt s3://mybucket2

Bucket 's3://mybucket2/' created

lizhedeMacBook-Pro:ca lizhe$ cd /

lizhedeMacBook-Pro:/ lizhe$ s3cmd mb --no-check-certificate s3://mybucket3

Bucket 's3://mybucket3/' created

lizhedeMacBook-Pro:/ lizhe$ 

https://docs.minio.io/docs/how-to-secure-access-to-minio-server-with-tls

https://github.com/minio/minio/tree/master/docs/tls/kubernetes

https://s3tools.org/download

Minio 入门 (1)

首先谈谈背景, 第一次听说Minio是在公司的一个基于AWS和Kubernetes的项目中, 这个项目本身的生产环境是 AWS上运行的Kubernetes集群, 但是本地开发环境使用的是docker swarm和minio

AWS , Kubernetes , docker swarm 这里就不老生常谈了, 那么minio 到底是个什么鬼

原来这个项目的图片在生产环境中是存储在S3桶上的, 本地开发环境中无法( 也可能是没钱 ) 让每个人都使用自己的s3桶, 所以我们使用了一个代替品

兼容亚马逊S3接口的minio , 既然接口是兼容的, 那么代码也就可以跨s3和minio使用了

minio可以方便的通过docker安装, 使用的端口是 9000, 数据的存储位置以参数形式决定

不过这里我的9000端口被portainer占用了, 所以我将 minio 的端口映射到9090

注意使用 -e MINIO_ACCESS_KEY=admin -e MINIO_SECRET_KEY=admin123456 配置了初始化用户名和密码

用户名要大于3个字符, 密码要在8到40个字符之间

Access key length should be between minimum 3 characters in length.

Secret key should be in between 8 and 40 characters.

lizhedeMacBook-Pro:study lizhe$ docker images | grep minio/minio

minio/minio              latest              a3e496686886        3 weeks ago         41.2MB

lizhedeMacBook-Pro:study lizhe$ docker ps

CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS              PORTS                    NAMES

68cafdfd8d42        portainer/portainer   "/portainer"        3 weeks ago         Up 3 hours          0.0.0.0:9000->9000/tcp   portainer

lizhedeMacBook-Pro:study lizhe$ docker run -p 9090:9000 --name studyminio -d -e MINIO_ACCESS_KEY=admin -e MINIO_SECRET_KEY=admin123456 minio/minio server /data

0215e71faa7e308ed175fe3e69dde784687b715210deed79fe6416ec195d2c59

lizhedeMacBook-Pro:study lizhe$ docker ps

CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                            PORTS                    NAMES

0215e71faa7e        minio/minio           "/usr/bin/docker-ent…"   5 seconds ago       Up 4 seconds (health: starting)   0.0.0.0:9090->9000/tcp   studyminio

68cafdfd8d42        portainer/portainer   "/portainer"             3 weeks ago         Up 3 hours                        0.0.0.0:9000->9000/tcp   portainer

lizhedeMacBook-Pro:study lizhe$ 

对象存储的优缺点在这里就不一一描述了, 你可以简单理解为 它比块存储(整个硬盘映射) 和 文件存储 都更灵活, 更容易实现CDN, 更容易在云环境下部署, 高可用等特点

然后我们来看一下如何通过S3cmd 来操作它

S3cmd is a CLI client for managing data in AWS S3, Google Cloud Storage or any cloud storage service provider that uses the s3 protocol. S3cmd is open source and is distributed under the GPLv2 license.

因为本地环境是Mac, 所以这里我选择使用pip来安装它, 先安装pip

lizhedeMacBook-Pro:~ lizhe$ sudo easy_install pip

然后安装 s3cmd

sudo pip install s3cmd

可惜的是使用官方文档中的上述命令, 并不能让我在macos上顺利安装 s3cmd 命令, 会得到一个错误

error: could not create ‘/System/Library/Frameworks/Python.framework/Versions/2.7/share’: Operation not permitted

这是因为EI Captain引入了SIP管理机制,所以旧版本的pip创建的文件目录操作被拒绝,包括使用root也是如此

解决办法是加入 –user 参数

sudo pip install s3cmd –user

将 s3cmd 加入环境变量

sudo vi ~/.bash_profile

lizhedeMacBook-Pro:~ lizhe$ cat ~/.bash_profile

VAGRANT_HOME="/Users/lizhe/Documents/vagrant_workspace/vagrant_home"

export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles

 

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home

export PATH=$JAVA_HOME/bin:$PATH

 

export PATH=/Users/lizhe/Library/Python/2.7/bin:$PATH

source ~/.bash_profile

sudo chmod +x /Users/lizhe/Library/Python/2.7/bin/s3cmd

创建一个配置文件 ~/.s3cfg

lizhedeMacBook-Pro:~ lizhe$ cat ~/.s3cfg

# Setup endpoint

host_base = localhost:9090

host_bucket = localhost:9090

bucket_location = us-east-1

use_https = False

 

# Setup access keys

access_key = admin

secret_key = admin123456

 

# Enable S3 v4 signature APIs

signature_v2 = False

lizhedeMacBook-Pro:~ lizhe$ 

尝试创建一个 bucket

lizhedeMacBook-Pro:~ lizhe$ s3cmd mb s3://mybucket

Bucket ‘s3://mybucket/’ created

可以看到 bucket 已经创建

Azure Monitoring

Azure 的 Monitoring 做的还是挺有意思的,尤其是可以从 Prometheus 端点直接读数据这个 

insights 侵入性好像有点强,不知道能不能像 istio 自动注入,如果能自动注入的话应该还可以