クラウドインフラ構築記

現在AWSの構築支援に携わっております。今注視しているのは、GKE、BigQuery、Google Dataflowなどサービスを展開しているGoolge Cloud Platformです。

2019年6月16日
から hiruta
BigQueryによる可視化、そして ML – “BigQuery GIS + ML on government open data” #gcpja #gcpug はコメントを受け付けていません。

BigQueryによる可視化、そして ML – “BigQuery GIS + ML on government open data” #gcpja #gcpug

BigQuery (BigQuery Geo Viz)を使って、Average Rent Percent Difference From Previous Yearの平均をDataprepでのデータマイニング
から、BigQuery Geo Vizへの可視化、BigQueryMLによる学習、推論まで書かれています。

https://medium.com/@williszhang/bigquery-gis-ml-on-government-open-data-2605ed9d2e8

ここでは、DataprepのReceipeについていくつかポイントを記載します。

 extractpositions col: {Facility Address} type: last count: 6 

Facility Addressに、”4733 BRADLEY BLVD CHEVY CHASE MD 20815″ と入っているが、
文字列のlast(最後末)を抜き出すときReceipe

Extract by positions
このfunctionsはスペースはカウントされないので、下記でトリムしてやる必要がある。

 textformat col: zipcode type: trimwhitespace 
 filter type: custom rowType: single row: ISMISMATCHED(zipcode, ['Zipcode']) action: Delete 

filter関数。vaildな値かどうかを判定して、rowを削除するかのアクションを設定することができる。

https://cloud.google.com/dataprep/docs/html/ISMISMATCHED-Function_57344747

このブログの例だと、Zip codeチェックに使用しています。
他にも、電話番号、E-Mail、クレジットカード、IPアドレス、URL、日付時間等のチェックができる。

Code Violations CSV. Wrangle recipe について

 drop col: {Date Assigned}: Drop 

としているが、BigQueryに登録するschemaで、Date_Assignedを指定しているので、Too many columneとなり怒られてしまう。


Code Violations CSV. Wrangle recipeから、”drop col: {Date Assigned}: Drop” をDelete(削除)することでbq loadできることは確認しています。

最終的にこんな感じになります。

Dataprep ML学習させる前に、イレギュラーなデータを除去できるDataprepの有益性を改めて実感。

2019年6月9日
から hiruta
Cloud Endpoints for Cloud Functions #gcpug #gcpja はコメントを受け付けていません。

Cloud Endpoints for Cloud Functions #gcpug #gcpja

BackendのCloud FunctionsのAPI managementできる Extensible Service Proxy(以下ESP)が可能に。
Google Accountによる認証、JSSON Web Token (JWT)などをESPで担うこともできる。
また、Cloud Endpointsにて、Quota制御なども

https://cloud.google.com/endpoints/docs/openapi/get-started-cloud-functions

Stackdriver loggingに下記が記録されているので、runtime自体nginxが動いていると思われる。

 2019-06-09 12:07:55.420 JST
2019/06/09 03:07:55 [warn] 1#1: Using trusted CA certificates file: /etc/nginx/trusted-ca-certificates.crt

手順は上記で使えるようになります。
ESP用のRuntimeを、Cloud Runでデプロイするようになります。

 gcr.io/endpoints-release/endpoints-runtime-serverless:1.30.0 

ENDPOINTS_SERVICE_NAMEを上記Cloud RunにデプロイしたRuntimeの環境変数に設定しておく必要があるが、
「Getting Started with Endpoints for Cloud Functions」のドキュメントには下記記載となっているが、ドキュメントが古いのか、configuurations updateコマンドはない。

 gcloud beta run configurations update \
--service CLOUD_RUN_SERVICE_NAME \
--set-env-vars ENDPOINTS_SERVICE_NAME=YOUR_SERVICE_NAME 

下記のようにする必要があります。

 gcloud beta run services update CLOUD_RUN_SERVICE_NAME \
--set-env-vars ENDPOINTS_SERVICE_NAME=YOUR_SERVICE_NAME 

Cloud FunctionsのIAM Supportで、Extensible Service Proxyからのトラフィックのみ通すこともできるようになります。
(ただし、本機能はαユーザのみ使うことが可能)

 gcloud alpha functions add-iam-policy-binding FUNCTION_NAME \
--member "serviceAccount:ESP_PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
--role "roles/cloudfunctions.invoker" 

JSON Web Token (JWT)による認証で、service accountを使う例。

https://cloud.google.com/endpoints/docs/openapi/service-account-authentication

上記チュートリアル内で、roles/serviceAccountTokenCreaterを、service accountの権限に付与するのだが、gcloudだと以下エラーとなってしまう。
console上だと問題ないのだが。

 $ gcloud projects add-iam-policy-binding PROJECT_ID --member serviceAccount:hello-test@PROJECT_ID.iam.gserviceaccount.com --role roles/serviceAccountTokenCreater
ERROR: Policy modification failed. For a binding with condition, run "gcloud alpha iam policies lint-condition" to identify issues in condition.
ERROR: (gcloud.projects.add-iam-policy-binding) INVALID_ARGUMENT: Role roles/serviceAccountTokenCreater is not supported for this resource. 

JWT token認証スキップしようとすると、下記となり、バックエンド(Cloud Functions)に飛ばなくなります。

 {
"code": 16,
"message": "JWT validation failed: Missing or invalid credentials",
"details": [
{
"@type": "type.googleapis.com/google.rpc.DebugInfo",
"stackEntries": [],
"detail": "auth"
}
]
}

また、Auth0、Firebaseなどとも連携できます。
Using Firebase to authenticate users https://cloud.google.com/endpoints/docs/openapi/authenticating-users-firebase
Using Auth0 to authenticate users https://cloud.google.com/endpoints/docs/openapi/authenticating-users-auth0

JWT validationのサンプルは下記で公開されています。
https://cloud.google.com/endpoints/docs/openapi/service-account-authentication#python

2019年2月17日
から hiruta
Cloud Data Loss Prevention (DLP) APIをpython にて試してみました。 #gcpja #gcpug はコメントを受け付けていません。

Cloud Data Loss Prevention (DLP) APIをpython にて試してみました。 #gcpja #gcpug

センシティブデータを検知、マスキングできるCloud Data Loss Prevention (DLP) APIを、pythonにて試してみた備忘録です。
Cloud DLP APIをおそらく、GCPしかなかったはず

まず、cloud DLP用のサービスアカウント作成します。

サービスアカウント作成

 gcloud iam service-accounts create dlp-api --display-name "dlp-api"

サービスアカウント用credentialsを発行

 gcloud iam service-accounts keys create ./key.json --iam-account dlp-api@xxxxxxxxxxxxxxxx.iam.gserviceaccount.com

dlp用の権限ロールを付与

 gcloud projects add-iam-policy-binding cms-production-1225 --member serviceAccount:dlp-api@xxxxxxxxxxxxxxxx.iam.gserviceaccount.com --role roles/dlp.user

gcloudで権限確認する場合は以下で。(gcloudでRequireされるpythonは2.7なので、DLPで必要なpythonとは差がある)

 gcloud auth activate-service-account --key-file key.json

Macとかローカル環境で試す場合は、環境変数にて

 export GOOGLE_APPLICATION_CREDENTIALS=../key.json

次に、Cloud DLP用のpyton moduleをインストール
https://googleapis.github.io/google-cloud-python/latest/dlp/index.html
Cloud DLPは、python 3.4以上をサポートしています。自分はpython 3.7.2で確認

https://googleapis.github.io/google-cloud-python/latest/dlp/index.htmlに記載しているサンプルコードそのままで動かなかった。上記サイトに記載しているサンプルは引数がAPIとは異なっているのが原因。ドキュメントのほうも更新してくれるといいのですが。

試したコードは以下になります。


from google.cloud import dlp_v2

client = dlp_v2.DlpServiceClient()

parent = client.project_path('xxxxxxxxxxxxxxxxxxx')
name = 'EMAIL_ADDRESS'
info_types_elements = {'name' : name }
info_types = [info_types_elements]
inspect_config = {'info_types' : info_types}

deidentify_config = {
'info_type_transformations': {
'transformations': [
{
'primitive_transformation': {
'character_mask_config': {
'masking_character': 'x',
'number_to_mask': 20
}
}
}
]
}
}
value = 'My email is not example@example.com , aaa@bbb.com , xxxx@xxxxx.co.jp '
items = {'value' : value }
response = client.deidentify_content(parent, deidentify_config,inspect_config, items)
print(response)

下記のようにメールアドレスをマスキングして出力してくれる。

 My email is not xxxxxxxxxxxxxxxxxxx , xxxxxxxxxxx , xxxxxxxxxxxxxxxx

取り込み時、Cloud Functions、Google dataflow等のロード処理で使ったりすると、マスキングしたデータができるので、本番そのまま検証に
もっていけないとかの場合に有益かと思います。

2019年1月20日
から hiruta
Stackdriver Trace for PHP で、wordpressサイトをモニタリングしてみました。 はコメントを受け付けていません。

Stackdriver Trace for PHP で、wordpressサイトをモニタリングしてみました。

Performance insightツールである、Stackdriver Trace for PHPを自運営しているwordpress環境に
組み込んでみました。

別は下記を参照します。

https://cloud.google.com/trace/docs/setup/php

まず、OpenCensus extension をインストール
peclコマンドがない場合は、apt install php7.2-devにて入れます。(Ubuntu 18.04.1 LTSの場合)

opencensus-alphaは、php7以上でないとインストールできません。

次に、comoserコマンドにより、OpenCensus Stackdriver exporter composer packageをインストール
直下にvendorフォルダが作成されます。

wp-config.phpに、下記を書き込めばOKです。

 

 

 

 

 

 

 

 

 

 

( https://opencensus.io/api/php/integrating-wordpress/)

GCEインスタンスの場合、Cloud API access scopesにおいて、 Stackdriver Trace がアクセスできるようにしておく
必要があります。

2018年12月15日
から hiruta
CloudBuild 事始め はコメントを受け付けていません。

CloudBuild 事始め

Container Builder 改め、CloudBuildについて、すこし試してみました。

CloudBuildの詳細についてはこちらです。
https://cloud.google.com/cloud-build/

CloudBuild用のコンテナを使って、CI処理を組んでいきます。対応ランタイムは下記となる。

Bazel、Curl、Docker、Dotnet、Gcloud、Git、Go、Gradle、Gsutil、Kubectl、Mvn、Npm、Wget、yarn

cloudbuild.ymlの例。Cloud Functionsのデプロイ例。Cloud Buildとリージョンちがくても問題はない。

 steps:
- name: gcr.io/cloud-builders/gcloud
args:
- "functions"
- "deploy"
- "http"
- "--entry-point=hello_test_http"
- "--region=us-central1"
- "--runtime=python37"
- "--trigger-http" 
 gcloud builds submit --config cloudbuild.yaml . 

権限周りではまったこを一点。

1度下記エラーがでたことがあった。

 Already have image (with digest): gcr.io/cloud-builders/gcloud
ERROR: (gcloud.beta.functions.deploy) ResponseError: status=[403], code=[Forbidden], message=[The caller does not have permission]
ERROR: build step 0 "gcr.io/cloud-builders/gcloud" failed: exit status 1

IAMの権限エラーによるものとなりますので、cloudbuildのserviceaccountに付与してやる必要がある

 gcloud iam service-accounts add-iam-policy-binding ${PROJECT}@appspot.gserviceaccount.com \
--member=serviceAccount:${NUM}@cloudbuild.gserviceaccount.com \
--role=roles/iam.serviceAccountUser --project=${PROJECT}

GCEインスタンスから、GCP APIを叩く場合も、同じく失敗することがあります。以前は大丈夫だったが、仕様が変更になったのか。

2018年12月4日
から hiruta
GCEのネットワークスループットについて はコメントを受け付けていません。

GCEのネットワークスループットについて

16vCPUsのインスタンス(n1-standard-16)で同ゾーンでネットワークスループットを計算しました。

GCEのインスタンスの場合、以下のようにコア毎に2GBpsの制限がある。8コア以上のインスタンスタイプの場合、16GBpsに制限されている。g1-small等の「shared-core machine type」は1GBpsに制限されている。

https://cloud.google.com/vpc/docs/quota?authuser=0#per_instance

1多重でした結果

 hiruta@instance-2:~$ iperf3 -c 10.80.10.2
[ ID] Interval Transfer Bandwidth Retr
[ 4] 0.00-10.00 sec 10.2 GBytes 8.72 Gbits/sec 3647 sender
[ 4] 0.00-10.00 sec 10.2 GBytes 8.72 Gbits/sec receiver

1多重で8GBps!

16多重で


hiruta@instance-2:~$ iperf3 -c 10.80.10.2 -P 16

[SUM] 0.00-10.00 sec 16.3 GBytes 14.0 Gbits/sec 173799 sender
[SUM] 0.00-10.00 sec 16.3 GBytes 14.0 Gbits/sec receiver

しっかり、16Gbpsで制限かかっているようだ。

2018年11月20日
から hiruta
Generating Signed URLs をgsutilコマンドにて #gcpug はコメントを受け付けていません。

Generating Signed URLs をgsutilコマンドにて #gcpug

Generating Signed URLsをgcloudでしてみました。

https://cloud.google.com/storage/docs/access-control/signing-urls-with-helpers

※aws s3 presignに相当する機能になります。

ConsoleではService accounsのページでservice account keysを作成できますが、gcloudでは、「roles/iam.serviceAccountKeyAdmin」を付与しないと、下記のエラーメッセージが出力されます。

$ gcloud iam service-accounts keys create ~/key.json --iam-account gcs-signurl2@xxxxxxxxxxxxxxxxxxx.iam.gserviceaccount.com
ERROR: (gcloud.iam.service-accounts.keys.create) PERMISSION_DENIED: Permission iam.serviceAccountKeys.create is required to perform this operation on service account projects/-/serviceAccounts/gcs-signurl2@xxxxxxxxxxxxxxxxxxx.iam.gserviceaccount.com.

まず、下記コマンドで権限付与しておく必要があります。

gcloud projects add-iam-policy-binding xxxxxxxxxxxxxxxxxxx --member serviceAccount:gcs-signurl@xxxxxxxxxxxxxxxxxxx.iam.gserviceaccount.com --role roles/iam.serviceAccountKeyAdmin

上記実行後に、gcloud iam service-accounts keys createコマンドを実行します。

次に、Generating Signed URLs with gsutilでテンポラリなURLを作成自体はできますが、テンポラリURLをブラウザからアクセスする場合、オブジェクトへの参照権限をサービスアカウントに付与しておく必要があります。

gcloud projects add-iam-policy-binding xxxxxxxxxxxxxxxxxxx --member=serviceAccount:gcs-signurl@xxxxxxxxxxxxxxxxxxx.iam.gserviceaccount.com --role=roles/storage.objectViewer

あとは、Generating Signed URLs with gsutilを実行すればテンポラリなURLを発行することができます。
(この場合10分間有効なURLとなります。)

$ gsutil signurl -d 10m Desktop/key.json gs://gcs-to-bigquery/2.5_month.csv
URL HTTP Method Expiration Signed URL
gs://gcs-to-bigquery/2.5_month.csv GET 2018-11-18 18:14:07

10分間経過すると下記エラーとなります。

<Error>
<Code>ExpiredToken</Code>
<Message>The provided token has expired.</Message>
<Details>
Request signature expired at: 2018-11-18T09:14:07+00:00
</Details>
</Error>

2018年7月29日
から hiruta
Cloud Functions To CloudSQL #gcpug はコメントを受け付けていません。

Cloud Functions To CloudSQL #gcpug

Cloud Functionsから直接接続できます。(CloudSQL Direct Connect)

公式には、Node.js版しか記載されていませんが、GCP Next SF 2018 でβになったpython 3.7でも可能なので、ポイントを記載します。

公式のCloudSQL Direct Connectは以下を参照してください。

https://cloud.google.com/functions/docs/sql

functionsデプロイ時に必要なモジュールを記載。(mysql-connector-python)

requirements.txt

 google-cloud-logging==1.6.0
mysql-connector-python==8.0.11

次にコード

CloudSQL接続情報とかをまず設定します。unix socketに対して接続する設定になります。


import mysql.connector

connectionName = 'gcp-project-id:asia-east1:web2-db'
config = {
'user': 'dbuser',
'password': 'xxxxxx',
'unix_socket': '/cloudsql/' + connectionName,
'database': 'database'
}

Cloud Functions python 3.7 runtimeは、Flask microframeworkというフレームワークでコーディングします。

 def hello_sql(request):
"""HTTP Cloud Function.
Args:
request (flask.Request): The request object.
Returns:
The response text, or any set of values that can be tuned into a
Response object using `make_response
<http://flask.pocoo.org/docs/0.12/api/#flask.Flask.make_response>`.
"""
request_json = request.get_json()
if request_json and 'exec_cmd' in request_json:
exec_cmd = request_json['exec_cmd']

ここで、ポイント

Connection Poolに接続するのが、max connection を1にすること

Functionsはイベントトリブンなので、コネクションリソースを枯渇することを防ぐ上で。

公式にも以下記載されています。

When using a connection pool, it is important to set the maximum connections to 1. This may seem counter-intuitive, however, creating more than one concurrent connection per function instance may cause rapid exhaustion of connection resources (see Maximum Concurrent Connections below for more detail). Cloud Functions limits concurrent executions to 1 per instance. This means you will never have a situation where two requests are being processed by a single function instance at the same time, so in most situations only a single database connection is needed.


try:
cnx = mysql.connector.connect(pool_name="mypool",
pool_size = 1,
**config)
exec_cmd = cnx.is_connected()
if cnx.is_connected():
cur = cnx.cursor()
cur.execute('select * from wp_options limit 1 ')
result = cur.fetchall()
except:
exec_cmd = cnx.is_connected()
finally:
cur.close()
cnx.close()

return f'Hello, {result}!' 

αテスト時は、event handlingがでなくても、デバッグしづらかったのですが、最近、python コードのエラーも場合でも、functionsがcrashした場合でも、Trackbackが出るようになっています。

2018年7月16日
から hiruta
HTTPS用にIngress リソースの作成について はコメントを受け付けていません。

HTTPS用にIngress リソースの作成について

Podsをexternalからアクセスさせるには、Serviceが必要になる。

上記Type LoadBalancer は、HTTPになるので、HTTPSは、Ingressを使う必要があります。

https://kubernetes.io/docs/concepts/services-networking/ingress/

IngressとPodの中継するため、NodePortを作っておきます。Ingressからヘルスチェックとして、NodePortを使います。

 kubectl expose deployment web-app --target-port=80 --type=NodePort 

Let’s encryptのSSL証明書はSecretsに登録しておきます。

 kubectl create secret tls custom-tls-cert 

ingress用のyaml

 apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: basic-ssl-ingress
spec:
tls:
- hosts:
- www.totalsolution.biz
secretName: custom-tls-cert
rules:
- host: www.totalsolution.biz
http:
paths:
- backend:
serviceName: web-app
servicePort: 80
path: / 

ヘルスチェックが通るまでしばらく時間がかかります。

2018年7月8日
から hiruta
kubernatesでRegional Persistent Disksを使うには #gcpug はコメントを受け付けていません。

kubernatesでRegional Persistent Disksを使うには #gcpug

Regional Persistent Disksについて

Persistent Disksは1ゾーンのみで使用できるものだが、Regional Persistent Disks は異なるゾーンにインスタンスにアタッチができる。
ディスクの内容はレプリケーションしてくれる。

regional persistent disks provide durable storage and replication of data between two zones in the same region.

Persistent Disksの作成

 gcloud beta compute disks create web-disk-2 --size 30GB --type pd-ssd --region asia-east1 --replica-zones asia-east1-a,asia-east1-b 

–replica-zonesに、2ゾーンを指定する。ただし、3 ゾーンを指定すると、–replica-zones: too many args となり、作成できない。

最初に作成されたディスクの確認をします。

 $ gcloud beta compute disks list
NAME LOCATION LOCATION_SCOPE SIZE_GB TYPE STATUS
web-disk-2 asia-east1 region 30 pd-ssd READY  

7/8現在、Web コンソールからはRegional Persistent Disksを確認できない。

regional diskのwriteモードでのアタッチは1インスタンスしかできないことは、Persistent Disksと同じ
Persistent Disksだと、ROMだと別のインスタンスにアタッチが可能

Regional Persistent Disksについては下記を参照してください。
https://cloud.google.com/compute/docs/disks/regional-persistent-disk

kubernatesでRegional Persistent Disksを使うには

regional diskをPersistentVolumeで使う場合、下記のように、PersistentVolumeを作成します
( failure-domain.beta.kubernetes.io/zoneタグが要)
※https://kubernetes.io/docs/concepts/storage/volumes/

 apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
failure-domain.beta.kubernetes.io/zone: asia-east1-a__asia-east1-b
spec:
storageClassName: manual
capacity:
storage: 30Gi
accessModes:
- ReadWriteOnce
gcePersistentDisk:
pdName: web-disk-2
fsType: ext4 

kubernetesのmaster versionは、1.10が必要(1.10.5-gke.0で動確)
それ以下だとPersistentVolumeでエラーとなります。

 $ kubectl create -f test.yml
Error from server (Forbidden): error when creating "test.yml": persistentvolumes "task-pv-volume" is forbidden: error querying GCE PD volume web-disk-2: The regional PD feature is only available via the GCE Alpha API. Enable "GCEDiskAlphaAPI" in the list of "alpha-features" in "gce.conf" to use the feature. 

次に、PersistentVolumeClaimの作成

 kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: task-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 30Gi
 $ kubectl create -f task-pv-claim.yml
persistentvolumeclaim "task-pv-claim" created
$ kubectl get pvc task-pv-claim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
task-pv-claim Bound task-pv-volume 30Gi RWO manual 9s
$ kubectl get pv task-pv-volume
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 30Gi RWO Retain Bound default/task-pv-claim manual 

task-pv-claimをPodからマウントするコンフィグを作成

 apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: web-app
labels:
app: WebApp
spec:
template:
metadata:
labels:
app: mysql-client
spec:
containers:
- name: web
image: asia.gcr.io/xxxxxxxxxxxxxxx/nginx:latest
ports:
- containerPort: 8080
env:
- name: WORDPRESS_DB_HOST
value: 127.0.0.1:3306
# These secrets are required to start the pod.
# [START cloudsql_secrets]
- name: WORDPRESS_DB_USER
valueFrom:
secretKeyRef:
name: cloudsql-db-credentials
key: username
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: cloudsql-db-credentials
key: password
# [END cloudsql_secrets]
volumeMounts:
- name: task-pv-storage
mountPath: /www
- name: php-fpm
image: asia.gcr.io/xxxxxxxxxxxxxxx/php-fpm:latest
ports:
- containerPort: 9000
# Change <INSTANCE_CONNECTION_NAME> here to include your GCP
# project, the region of your Cloud SQL instance and the name
# of your Cloud SQL instance. The format is
# $PROJECT:$REGION:$INSTANCE
# [START proxy_container]
- name: cloudsql-proxy
image: gcr.io/cloudsql-docker/gce-proxy:1.11
command: ["/cloud_sql_proxy",
"-instances=xxxxxxxxxxxxxxx:asia-east1:web2-db=tcp:3306",
"-credential_file=/secrets/cloudsql/credentials.json"]
volumeMounts:
- name: cloudsql-instance-credentials
mountPath: /secrets/cloudsql
readOnly: true
# [END proxy_container]
# [START volumes]
volumes:
- name: cloudsql-instance-credentials
secret:
secretName: cloudsql-instance-credentials
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
# [END volumes] 
 kubectl apply -f deployment.yml 

でデプロイし、Podにログインして、Regional Persistent Disksが、マウントされていることを確認しました。

 root@web-app-84dcf8d8c8-vdnjp:/# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 100G 0 disk
|-sda1 8:1 95.9G 0 part /etc/hosts
|-sda2 8:2 0 16M 0 part
|-sda3 8:3 0 2G 0 part
|-sda4 8:4 0 16M 0 part
|-sda5 8:5 0 2G 0 part
|-sda6 8:6 512B 0 part
|-sda7 8:7 0 512B 0 part
|-sda8 8:8 16M 0 part
|-sda9 8:9 0 512B 0 part
|-sda10 8:10 0 512B 0 part
|-sda11 8:11 8M 0 part
`-sda12 8:12 0 32M 0 part
sdb 8:16 0 30G 0 disk /www