從零開始的容器工程師

首先

感謝各位

關於自我介紹

Michael.K

  • 百臂股份有限公司
    • Developer
  • 時間軸科技股份有限公司
    •  Sr. Principal Developer
  • 遠時(friDay)科技股份有限公司
    • Sr. Principal Developer
  • I.X Security
    • Sr. Principal Software Engineer
  • CapsLock, Studio

今天主要的目標

什麼是docker

將OS Application化

認真說起來

docker經歷過兩個朝代

在docker 1.10前

  • 依賴LXC、libvirt、systemd-nspawn
  • LXC還是需要一個較完整的VM

在docker 1.10(含)後

  • libcontainer
  • 完全擺脫LXC的依賴
  • 全部由golang打造
  • 需要linux kernel 3.10(所以CentOS不一定能用)

那docker是怎麼運作的

先介紹一些元件

Repository

  • 就像是apt、brew或是yum的來源一樣
  • 存了很多image (Package)

Image

  • 相當於Package
  • 有多個layer(層),每個layer都紀錄了檔案資料
  • 每一層的layer都有一個特殊的hash
  • 這個hash可能可以在不同image出現

Container

  • 由image建立而成
  • 相當於一個一個的程式
  • 必須要有一個foreground在跑的程式

Network

  • 主要分為幾種
    • none
    • bridge
    • overlay
    • container
    • host

docker生命週期

  1. client呼叫docker daemon
  2. docker daemon與host network / host cgroups溝通
  3. 判斷docker container是否存在
  4. 從local image將layer解開
  5. 如果local image不存在的話從repository拿
  6. 建立docker container

基本的架構解釋完了

關於安裝的部份

只需要curl

curl https://get.docker.com | bash

或是上docker store

如何操作docker呢

docker有一個共用倉庫

幾個常見的docker指令

  • image
    • docker run
    • docker images
    • docker rmi
  • container
    • docker exec
    • docker ps
    • docker logs
    • docker stats
    • docker start
    • docker stop
    • docker restart
    • docker rm

譬如最常見的

docker run / exec

docker run

啟動 container

docker exec

執行container的指令

# 起一個在背景使用shell的服務
bash-3.2$ docker run -i -t -d nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
be8881be8156: Already exists 
65206e5c5e2d: Pull complete 
8e029c3e2376: Pull complete 
Digest: sha256:291e15f504cdc40aeedcd29b59f0079c794e18f22cd8a6a6d66d646b36f1d51b
Status: Downloaded newer image for nginx:latest
73ac5cf4f67f64ed5eb4e4c6e97bad6b037cdd3097b24799dacc536b6f621c9a

# 這樣就可以進去nginx了
bash-3.2$ docker exec -ti 73 bash
root@73ac5cf4f67f:/#

如果要給別人用怎麼辦

docker run -i -t -d -p 80:80 nginx

如果服務遇到意外中斷

docker run -i -t -d -p 80:80 --restart always nginx

如果要連node.js

docker run -i -d -t -p 80:80 --link node nginx

如何寫docker image

先有一個認知

container是獨立元件

設計儘量可以獨立

關於寫image的部份

介紹一些常用的關鍵字

常用的關鍵字

  • FROM
  • RUN
  • ARG
  • ADD
  • COPY
  • ENV
  • ENTRYPOINT
  • CMD
  • VOLUME
  • WORKDIR

輕便、簡單、快速

Docker ❤️ Alpine Linux

Alpine Linux

  • 體積非常的小 (5MB)
  • 有完整的Linux架構
  • 豐富的元件支援

可以在使用前先看tag

FROM nginx:alpine

ARG DOMAIN

ENV DOMAIN=$DOMAIN

COPY default.conf /etc/nginx/conf.d/default.conf

ENTRYPOINT ["nginx", "-g", "daemon off;"]

建立docker image指令會是這樣

docker build . -t image:tag --build-arg DOMAIN=example.com

這時候你一定會有一個問題

ARG vs ENV

一些小變化

# 如果FOO有資料的話就是叫做FOO,如果沒的話就是叫做bar

${FOO:+bar}

# 如果FOO沒資料的話就是empty(空值),如果有的話就是bar

${FOO:-bar}

COPY vs ADD

(COPY && ADD) vs VOLUME

CMD vs ENTRYPOINT

CMD跟ENTRYPOINT

  • CMD是在docker run起的指令
    • docker run -ti php
  • ENTRYPOINT是在container起來時的指令,必須不會中斷

新的問題來了

公司的code不能外流

如何架私有的repository

Text

gcr.io

AWS ECS

GitLab Container Registry

或是自架的方案

Harbor

就我個人而言...

再來就可以上傳了

# 先把需要上傳的container包裝成 domain/project(group)/name 的image
docker commit container registry.gitlab.com/sample/code:latest

# 登入registry
docker login -u user -p password registry.gitlab.com

# 將image上傳到registry
docker push registry.gitlab.com/sample/code:latest

# 使用上傳的image建立container
docker run -i -d -t registry.gitlab.com/sample/code:latest

從頭開始起新的docker

一定會遇到的問題...

  • container要怎麼使用?
  • 怎麼將各種container連在一起?

可以試看看

docker-compose

docker-compose

  • 主要由兩個部份組成(services、version)
  • service內定義名稱,並且所有的服務都能靠名稱溝通
version: "3"
services:
  php:
    build:
      context: .
      dockerfile: Dockerfile-php
    restart: always
    env_file:
      - ./.env
    volumes:
      - ./php:/src
  db:
    container_name: tickets-db
    image: mariadb:10
    restart: always
    volumes:
      - ./db:/var/lib/mysql
    environment:
      - MYSQL_DATABASE=${DB_DATABASE}
      - MYSQL_USER=${DB_USERNAME}
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - MYSQL_RANDOM_ROOT_PASSWORD=true
  web:
    image: nginx:1.15.2-alpine
    restart: always
    ports:
      - 80:80
      - 443:443
    depends_on:
      - php
      - db
      - redis
    volumes:
      - ./php:/src
      - ./web:/etc/nginx/conf.d
  redis:
    image: redis:4.0.11-alpine
    restart: always

示範如何從零開始

沒辦法安裝的請用這個

docker後呢? 試看看叢集

kops

首先你需要一個IAM

  • AmazonEC2FullAccess
  • AmazonRoute53FullAccess
  • AmazonS3FullAccess
  • IAMFullAccess
  • AmazonVPCFullAccess

並且確定有裝awscli

沒有帳號的先不用緊張

export AWS_ACCESS_KEY_ID=
export AWS_SECRET_ACCESS_KEY=
export AWS_DEFAULT_REGION=
export KOPS_STATE_STORE=
export NAME=cluster.k8s.local

# 如果已經有的可以省略
aws s3api create-bucket --bucket $KOPS_STATE_STORE \
  --create-bucket-configuration LocationConstraint=ap-northeast-1

kops create cluster --master-size t2.small \
  --node-size t2.small --zones ap-northeast-1a $NAME

# 等待大約兩分鐘
kubectl get nodes

如果看到有東西

代表更進一步了

接下來介紹各種角色

先說明一下Kubernetes的組成

關於k8s的設定

  • apiVersion
  • metadata
  • kind
  • spec

Node

  • 就是指主機
  • 包含master、node
  • master是控制node的主要角色
  • master一般不會部署運算單元

Pod

  • Kubernetes的運算最小單位
  • 可以由多個docker container組成
  • 在Pod內可以取用localhost port到對應container

Deployment

  • 建立基礎的Pod
  • 定義Pod的行為

Service

  • 分為三種類型
    • NodePort: 透過master node port可以連接
    • ClusterIP: 在k8s cluster內的位置
    • LoadBalancer: 對外的load balancer(e.g. ELB)
  • 透過ClusterIP可以在Pod內導到對應服務

這時候一定會踩到的點

KOPS的ELB是Classic Elastic Load Balancer

無法使用WebSocket

Secret

  • 可以是檔案或是yaml
  • 主要分為三種
    • generic
      • 儲存任何知道的機敏資料,並且可以作為env引入
    • docker-registry
      • 儲存docker private repo使用的帳號密碼
    • tls
      • https使用的簽章
1
1

Ingress

  • k8s內的route rule(load balancer)
  • 可以將對應的domain導到不同service
  • 或是產生一個LoadBalancer,將對應host流量統一導出
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-world-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.org/ssl-services: "hello-world-svc"
spec:
  tls:
    - hosts:
      - api.sample.com
      secretName: tls-certificate
  rules:
  - host: api.sample.com
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-world-svc
          servicePort: 8080

對照docker呢

k8s與docker指令對照

docker kubernetes
docker run kubectl run/kubectl create deployment
docker ps kubectl get pods
docker attach kubectl attach
docker exec kubectl exec
docker logs kubectl top pod

實作部署自己的服務

以及擴容方案

Q&A

Thanks

簡報

HWD TG

CapsLock, Studio

Event TG

從零開始的容器工程師

By michael34435

從零開始的容器工程師

  • 1,258