除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
继续阅读Go+Docker完美适配微服务
Author: tony
Jenkins+Gitlab Webhook触发构建获取参数
可以在Gitlab编辑webhook界面看到test请求的详情和返回输出。
至于在jenkins的shell脚本中也可以取到这些变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | echo $gitlabSourceRepoURL echo $gitlabAfter echo $gitlabTargetBranch echo $gitlabSourceRepoHttpUrl echo $gitlabMergeRequestLastCommit echo $gitlabSourceRepoSshUrl echo $gitlabSourceRepoHomepage echo $gitlabBranch echo $gitlabSourceBranch echo $gitlabUserEmail echo $gitlabBefore echo $gitlabSourceRepoName echo $gitlabSourceNamespace echo $gitlabUserName |
laravel-mix npm构建报错node-sass
报错
1 | gyp WARN EACCES attempting to reinstall using temporary dev dir "/pathtoproject/node_modules/node-sass/.node-gyp" |
解决
1 | npm install --unsafe-perm --verbose node-sass |
mark一下。
Centos6安装mysql5.7.18
今天安装一下二进制包的mysql5.7版本,绿色版用起来清爽!
继续阅读Centos6安装mysql5.7.18
sync.Pool go对象池
一个sync.Pool对象就是一组临时对象的集合。Pool是协程安全的。
Pool用于存储那些被分配了但是没有被使用,而未来可能会使用的值,以减小垃圾回收的压力。一个比较好的例子是fmt包,fmt包总是需要使用一些[]byte之类的对象,golang建立了一个临时对象池,存放着这些对象,如果需要使用一个[]byte,就去Pool里面拿,如果拿不到就分配一份。
这比起不停生成新的[]byte,用完了再等待gc回收来要高效得多。
继续阅读sync.Pool go对象池
Go Sync包详解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | package main; import ( "fmt" "sync" "runtime" "time" ) //加锁,注意锁要以指针的形式传进来,不然只是拷贝 func total1(num *int, mu *sync.Mutex, ch chan bool) { mu.Lock(); for i := 0; i < 1000; i++ { *num += i; } ch <- true; mu.Unlock(); } //不加锁 func total2(num *int, ch chan bool) { for i := 0; i < 1000; i++ { *num += i; } ch <- true; } //Lock、Unlock与RLock、RUnlock不能嵌套使用 func total3(num *int, rwmu *sync.RWMutex, ch chan bool) { for i := 0; i < 1000; i++ { rwmu.Lock(); *num += i; rwmu.Unlock(); if(i == 500) { //读锁定 rwmu.RLock(); fmt.Print(*num, " "); rwmu.RUnlock(); } } ch <- true; } func printNum(num int, cond *sync.Cond) { cond.L.Lock(); if num < 5 { //num小于5时,进入等待状态 cond.Wait(); } //大于5的正常输出 fmt.Println(num); cond.L.Unlock(); } func main() { //Once.Do()保证多次调用只执行一次 once := sync.Once{}; ch := make(chan bool, 3); for i := 0; i < 3; i++ { go func(n int) { once.Do(func() { //只会执行一次,因为闭包引用了变量n,最后的值为2 fmt.Println(n) }); //给chan发送true,表示执行完成 ch <- true; }(i); } for i := 0; i < 3; i++ { //读取三次chan,如果上面三次没执行完会一直阻塞 <-ch; } //互斥锁,保证某一时刻只能有一个访问对象 mutex := sync.Mutex{}; ch2 := make(chan bool, 20); //使用多核,不然下面的结果会一样 runtime.GOMAXPROCS(runtime.NumCPU()); num1 := 0; num2 := 0; for i := 0; i < 10; i++ { go total1(&num1, &mutex, ch2); } for i := 0; i < 10; i++ { go total2(&num2, ch2); } for i := 0; i < 20; i++ { <-ch2; } //会发现num1与num2计算出的结果不一样 //而num1的结果才是正确的,因为total2没有加锁,导致多个goroutine操作num时发生数据混乱 fmt.Println(num1, num2); //读写锁,多了读锁定,和读解锁,让多个goroutine同时读取对象 rwmutex := sync.RWMutex{}; ch3 := make(chan bool, 10); num3 := 0; for i := 0; i < 10; i++ { go total3(&num3, &rwmutex, ch3); } for i := 0; i < 10; i++ { <-ch3; } fmt.Println(num3); //组等待,等待一组goroutine的结束 wg := sync.WaitGroup{}; //增加计数器 wg.Add(10); for i:= 0; i< 10; i++ { go func(n int) { fmt.Print(n, " "); //这里表示该goroutine执行完成 wg.Done(); }(i); } //等待所有线程执行完成 wg.Wait(); fmt.Println(""); //条件等待 mutex2 := sync.Mutex{}; //使用锁创建一个条件等待 cond := sync.NewCond(&mutex2); for i := 0; i < 10; i++ { go printNum(i, cond); } time.Sleep(time.Second * 1); //等待一秒后,我们先唤醒一个等待,输出一个数字 cond.L.Lock() cond.Signal(); cond.L.Unlock(); time.Sleep(time.Second * 1); //再次待待一秒后,唤醒所有,输出余下四个数字 cond.L.Lock() cond.Broadcast(); cond.L.Unlock(); time.Sleep(time.Second * 1); } |
Go定时任务time详解
我们总是会使用Timer去执行一些定时任务,最近在Go语言的定时器使用上面不小心踩到一点问题,这里记录一下。
继续阅读Go定时任务time详解
mac php curl https问题修复
mac中自带的curl和PHP版本可能不兼容,或者其他原因,在未安装curl时总是无法调用https,提示SSL certificate problem: Couldn’t understand the server certificate format.
使用以下命令重装php调用外部curl搞定!
1 2 3 | xcode-select --install brew uninstall --ignore-dependencies php71 brew install php71 --with-homebrew-curl |
Go与php的加密通信aes-128-ecb
通过go语言进行加密,可利用php openssl扩展进行解密。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | package encrypt import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "fmt" ) type ecb struct { b cipher.Block blockSize int } func newECB(b cipher.Block) *ecb { return &ecb{ b: b, blockSize: b.BlockSize(), } } type ecbEncrypter ecb // NewECBEncrypter returns a BlockMode which encrypts in electronic code book // mode, using the given Block. func NewECBEncrypter(b cipher.Block) cipher.BlockMode { return (*ecbEncrypter)(newECB(b)) } func (x *ecbEncrypter) BlockSize() int { return x.blockSize } func (x *ecbEncrypter) CryptBlocks(dst, src []byte) { if len(src)%x.blockSize != 0 { panic("crypto/cipher: input not full blocks") } if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } for len(src) > 0 { x.b.Encrypt(dst, src[:x.blockSize]) src = src[x.blockSize:] dst = dst[x.blockSize:] } } type ecbDecrypter ecb // NewECBDecrypter returns a BlockMode which decrypts in electronic code book // mode, using the given Block. func NewECBDecrypter(b cipher.Block) cipher.BlockMode { return (*ecbDecrypter)(newECB(b)) } func (x *ecbDecrypter) BlockSize() int { return x.blockSize } func (x *ecbDecrypter) CryptBlocks(dst, src []byte) { if len(src)%x.blockSize != 0 { panic("crypto/cipher: input not full blocks") } if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } for len(src) > 0 { x.b.Decrypt(dst, src[:x.blockSize]) src = src[x.blockSize:] dst = dst[x.blockSize:] } } func encodeBase64(b []byte) string { return base64.StdEncoding.EncodeToString(b) } func decodeBase64(s string) []byte { data, err := base64.StdEncoding.DecodeString(s) if err != nil { panic(err) } return data } func PKCS5Padding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } func PKCS5UnPadding(origData []byte) []byte { length := len(origData) // 去掉最后一个字节 unpadding 次 unpadding := int(origData[length-1]) return origData[:(length - unpadding)] } func EncryptECB(src string, hexKey string) string { var hasError = false block, err := aes.NewCipher([]byte(hexKey)) if err != nil { fmt.Println("key error") hasError = true } if src == "" { fmt.Println("plain content empty") hasError = true } if hasError { return "" } ecbn := NewECBEncrypter(block) content := []byte(src) content = PKCS5Padding(content, block.BlockSize()) crypted := make([]byte, len(content)) ecbn.CryptBlocks(crypted, content) return base64.StdEncoding.EncodeToString(crypted) } func DecryptECB(src string, hexKey string) string { var hasError = false block, err := aes.NewCipher([]byte(hexKey)) if err != nil { fmt.Println("key error") hasError = true } if src == "" { fmt.Println("plain content empty") hasError = true } if hasError { return "" } ecbn := NewECBDecrypter(block) content := decodeBase64(src) //fmt.Println(content) //content = PKCS5Padding(content, block.BlockSize()) crypted := make([]byte, len(content)) ecbn.CryptBlocks(crypted, content) return string(PKCS5UnPadding(crypted)) } |
简单几条命令搭建共享式samba
有时候在公司需要一个共享的空间,samba最适合做这个,不需要太高的安全级别,只是最简单方便的文件共享 。
1 2 3 | yum install samba chkconfig smb on vim /etc/samba/smb.conf |
调配置文件的两个地方,第一个改为share用户模式,并设置用户为root.
继续阅读简单几条命令搭建共享式samba