概要 †Drone の pipeline から 同一ホスト上で稼働する別のコンテナの再起動などを行ったみた。 目次 †必要な設定 †drone のパイプラインから 他の docker コンテナの停止や起動などを行う場合、以下の設定が必要となる。 /var/run/docker.sock のマウント †runner で /var/run/docker.sock を参照できる必要があるので為、以下の通り /var/run/docker.sock をマウントしておく。 kind: pipeline type: docker name: default steps: - name: "build and push to registry" image: docker/compose volumes: - name: dockersock path: /var/run/docker.sock commands: : volumes: - name: dockersock host: path: /var/run/docker.sock docker login †プライベートなレジストリへの push や pull を行う前の docker login では コマンドにパスワードを含まない用に考慮する。 kind: pipeline type: docker name: default steps: - name: "build and push to registry" image: docker/compose volumes: - name: registrypwd path: /tmp/registry-password commands: # プライベートレジストリに docker login (パスワードはホスト側のファイルから取得) - "cat /tmp/registry-password | docker login ${REGISTRY_NAME} --username ${REGISTRY_USER} --password-stdin" : volumes: - name: registrypwd host: path: /path/to/registry-password サンプル †環境イメージ †Azure 上に 以下の環境を作って検証してみた。 環境作成 †#!/bin/bash PREFIX=XXXXXXX subscriptionId=XXXXXXXXXXXXXXXXXXXXXXXXXX region=japanwest # リソースグループ resourceGroup=${PREFIX}Resources # 仮想ネットワーク vnetName=${PREFIX}VNet vnetPrefix=10.1.0.0/16 # セキュリティグループ名 nsgName=${vnetName}SecGrp nsgPubRuleName=${nsgName}PubRule # 仮想マシンを配置するサブネット vmSubnetName=${PREFIX}VmSubnet vmSubnetPrefix=10.1.1.0/24 # 仮想マシンの情報 vmName=${PREFIX}Vm vmImage=UbuntuLTS vmIpAddress=10.1.1.5 vmUser=sample # コンテナレジストリ名(Prefix) registryName=${PREFIX}registry #!/bin/bash # 設定の読み込み source 0_env.sh # リソース作成 if [ "$1" == "--create" ]; then # リソースグループの作成 echo "az group create" az group create --name $resourceGroup --location $region # NSG(ネットワークセキュリティグループの)作成 echo "az network nsg create" az network nsg create --resource-group $resourceGroup --name $nsgName # NSGルール(80番ポート) echo "az network nsg rule create(80)" az network nsg rule create \ --resource-group $resourceGroup --nsg-name $nsgName --name ${nsgPubRuleName}1\ --access Allow --protocol Tcp --direction Inbound --priority 100 \ --source-address-prefix Internet --source-port-range "*" --destination-port-range "80" # NSGルール(443番ポート) echo "az network nsg rule create(443)" az network nsg rule create \ --resource-group $resourceGroup --nsg-name $nsgName --name ${nsgPubRuleName}2 \ --access Allow --protocol Tcp --direction Inbound --priority 101 \ --source-address-prefix Internet --source-port-range "*" --destination-port-range "443" # NSGルール(22ポート) echo "az network nsg rule create(ssh)" az network nsg rule create \ --resource-group $resourceGroup --nsg-name $nsgName --name ${nsgPubRuleName}3 \ --access Allow --protocol Tcp --direction Inbound --priority 1000 \ --source-address-prefix Internet --source-port-range "*" --destination-port-range "22" # 仮想ネットワーク 及び サブネット作成 echo "az network vnet create" az network vnet create \ --name $vnetName --resource-group $resourceGroup \ --address-prefixes $vnetPrefix --network-security-group $nsgName \ --subnet-name $vmSubnetName --subnet-prefixes $vmSubnetPrefix # コンテナレジストリ作成 echo "az acr create ( $registryName )" az acr create -n $registryName -g $resourceGroup --sku standard --admin-enabled true # レジストリユーザ名/パスワード取得 acr_credential="`az acr credential show --name $registryName -o table | tail -1`" registryUser="`echo "$acr_credential" | awk '{print $1}'`" registryPwd="`echo "$acr_credential" | awk '{print $2}'`" # 初版のDockerイメージをビルドしてACRに登録 #echo "az acr build ( $appImageName )" #echo az acr build --registry $registryName --image ${appImageName} -f ./sample-app1/Dockerfile ./sample-app1 #az acr build --registry $registryName --image ${appImageName} -f ./sample-app1/Dockerfile ./sample-app1 # VMセットアップスクリプト作成(環境変数を埋め込み) cat 2_setup_vm.tmpl \ | sed "s/###REGISTRY_USER###/${registryUser}/g" \ | sed "s/###REGISTRY_PWD###/${registryPwd}/g" > 2_setup_vm.sh chmod 755 2_setup_vm.sh # 仮想マシンの作成 rm -rf ~/.ssh/id_rsa rm -rf ~/.ssh/id_rsa.pub echo "az vm create" az vm create \ --resource-group $resourceGroup --name $vmName --image $vmImage --generate-ssh-keys \ --vnet-name $vnetName --subnet $vmSubnetName \ --private-ip-address $vmIpAddress --admin-username $vmUser \ --public-ip-address-dns-name `echo $vmName | tr '[A-Z]' '[a-z]'` \ --custom-data 2_setup_vm.sh # ポート開放 echo "az vm open-port(80)" az vm open-port --resource-group $resourceGroup --name $vmName --port 80 --priority 901 echo "az vm open-port(443)" az vm open-port --resource-group $resourceGroup --name $vmName --port 443 --priority 902 # 生成されたSSH鍵を退避しておく mkdir -p pem if [ -e ~/.ssh/id_rsa ]; then mv ~/.ssh/id_rsa ./pem/id_rsa_${vmName} mv ~/.ssh/id_rsa.pub ./pem/id_rsa_${vmName}.pub fi # giteaのURLを表示 echo GITEA ... https://${vmName}.${region}.cloudapp.azure.com/gitea | tr [A-Z] [a-z] echo DRONE ... https://${vmName}.${region}.cloudapp.azure.com | tr [A-Z] [a-z] echo Sample App ... https://${vmName}.${region}.cloudapp.azure.com/sample-app1 | tr [A-Z] [a-z] fi # リソース削除 if [ "$1" == "--delete" ]; then echo az group delete az group delete --name $resourceGroup fi # URL表示 if [ "$1" == "--env" ]; then echo GITEA ... https://${vmName}.${region}.cloudapp.azure.com/gitea | tr [A-Z] [a-z] echo DRONE ... https://${vmName}.${region}.cloudapp.azure.com | tr [A-Z] [a-z] echo Sample App ... https://${vmName}.${region}.cloudapp.azure.com/sample-app1 | tr [A-Z] [a-z] fi #!/bin/bash apt-get update apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose # set server name region=japanwest hostname=`hostname | tr [A-Z] [a-z]` server_name="${hostname}.${region}.cloudapp.azure.com" # make and change directory mkdir -p /tmp/docker_container cd /tmp/docker_container #-------------------------------------- # wait until azure dns name is available. # (If it is NG after waiting 5 minutes, give up..) #-------------------------------------- for i in `seq 30`; do x=`host $server_name` if [ "$?" == "0" ]; then break fi sleep 10 done #-------------------------------------- # get ssl certificate. #-------------------------------------- sudo docker run --rm -p 80:80 \ -v /etc/letsencrypt:/etc/letsencrypt \ -v /etc/letsencrypt/logs:/var/log/letsencrypt \ certbot/certbot certonly --standalone \ -d $server_name \ --register-unsafely-without-email \ --non-interactive --agree-tos \ --force-renewal \ --renew-by-default \ --preferred-challenges http #-------------------------------------- # create default.conf for nginx. #-------------------------------------- cat <<_EO_DEFAULT_CONF_>default.conf # http server{ listen 80; listen [::]:80; server_name ${server_name}; return 301 https://\$host\$request_uri; } # https server{ listen 443 ssl; listen [::]:443 ssl; server_name ${server_name}; ssl_certificate /etc/letsencrypt/live/${server_name}/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/${server_name}/privkey.pem; location /sample-app1/ { proxy_pass http://sample-app1/; } location /gitea/ { proxy_pass http://gitea-app:3000/; } location / { proxy_pass http://drone-app/; } } _EO_DEFAULT_CONF_ #-------------------------------------- # set REGISTRY_NAME to environments. #-------------------------------------- #export REGISTRY_NAME=###REGISTRY_USER###.azurecr.io #-------------------------------------- # make .env #-------------------------------------- cat <<_EO_ENV_>.env GITEA_HOST=${server_name} GITEA_USER_GID=1000 GITEA_USER_UID=1000 GITEA_DB_HOST=gitea-db:5432 GITEA_DB_NAME=gitea GITEA_DB_PASSWD=gitea GITEA_DB_PASSWORD=gitea GITEA_DB_USER=gitea DRONE_HOST=${server_name} DRONE_GITEA_CLIENT_ID= DRONE_GITEA_CLIENT_SECRET= DRONE_RPC_SECRET=secret DRONE_RUNNER_CAPACITY=2 REGISTRY_NAME=###REGISTRY_USER###.azurecr.io REGISTRY_USER=###REGISTRY_USER### _EO_ENV_ #-------------------------------------- # registry password. #-------------------------------------- echo "###REGISTRY_PWD###">registry-password # # make docker-compose.yml # cat <<_EO_DOCKER_COMPOSE_>docker-compose.yml version: "3" services: gitea-proxy: image: nginx:latest hostname: gitea-proxy container_name: gitea-proxy ports: - "80:80" - "443:443" volumes: - ./default.conf:/etc/nginx/conf.d/default.conf - /etc/letsencrypt:/etc/letsencrypt links: - gitea-app depends_on: - gitea-app gitea-app: image: gitea/gitea:latest hostname: gitea-app container_name: gitea-app environment: USER_UID: "\${GITEA_USER_UID}" USER_GID: "\${GITEA_USER_GID}" ROOT_URL: "https://\${GITEA_HOST}/gitea" DB_TYPE: "postgres" DB_HOST: "\${GITEA_DB_HOST}" DB_NAME: "\${GITEA_DB_NAME}" DB_USER: "\${GITEA_DB_USER}" DB_PASSWD: "\${GITEA_DB_PASSWD}" DISABLE_SSH: "true" #SSH_DOMAIN: "\${GITEA_HOST}" #SSH_PORT: "\${GITEA_SSH_PORT}" SKIP_TLS_VERIFY: "true" TZ: "Japan" volumes: - ./volumes/gitea-app:/data links: - gitea-db gitea-db: image: postgres:latest hostname: gitea-db container_name: gitea-db volumes: - ./volumes/gitea-db:/var/lib/postgresql/data environment: POSTGRES_DB: "\${GITEA_DB_NAME}" POSTGRES_USER: "\${GITEA_DB_USER}" POSTGRES_PASSWORD: "\${GITEA_DB_PASSWD}" drone-app: image: drone/drone:latest hostname: drone-app container_name: drone-app environment: links: - gitea-app depends_on: - gitea-app environment: DOCKER_API_VERSION: "1.39" DRONE_AGENT_ENABLED: "true" DRONE_GITEA_SERVER: "https://\${GITEA_HOST}/gitea" DRONE_GITEA_CLIENT_ID: "\${DRONE_GITEA_CLIENT_ID}" DRONE_GITEA_CLIENT_SECRET: "\${DRONE_GITEA_CLIENT_SECRET}" DRONE_RPC_SECRET: "\${DRONE_RPC_SECRET}" DRONE_SERVER_HOST: "\${DRONE_HOST}" DRONE_SERVER_PROTO: "https" DRONE_USER_CREATE: "username:droneadmin,admin:true" DRONE_GITEA_SKIP_VERIFY: "true" DRONE_GITEA_ALWAYS_AUTH: "false" DRONE_TLS_AUTOCERT: "false" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./volumes/drone-app:/var/lib/drone drone-runner: image: drone/drone-runner-docker:latest hostname: drone-runner container_name: drone-runner links: - drone-app - gitea-app volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./.env:/etc/drone.env:ro environment: DOCKER_API_VERSION: "1.39" DRONE_RPC_PROTO: "https" #DRONE_RPC_HOST: "\${DRONE_HOST}:\${DRONE_PORT}" DRONE_RPC_HOST: "\${DRONE_HOST}" DRONE_RPC_SECRET: "\${DRONE_RPC_SECRET}" DRONE_RUNNER_CAPACITY: "\${DRONE_RUNNER_CAPACITY}" DRONE_RUNNER_NAME: "drone-runner" DRONE_RUNNER_ENV_FILE: "/etc/drone.env" DRONE_TRACE: "true" DRONE_RPC_DUMP_HTTP: "true" DRONE_RPC_DUMP_HTTP_BODY: "true" #DRONE_RUNNER_NETWORKS: my-network networks: default: external: name: my_network _EO_DOCKER_COMPOSE_ #-------------------------------------- # create docker network #-------------------------------------- docker network create my_network #-------------------------------------- # start sample-app1(dummy). #-------------------------------------- docker run --rm --network my_network --hostname sample-app1 --name sample-app1 -d nginx #-------------------------------------- # start ci/cd containers #-------------------------------------- docker-compose up -d (1) Azure環境の作成 ./1_create_vm.sh --create : : gitea ... https://xxxxxxxxx.japanwest.cloudapp.azure.com/gitea drone ... https://xxxxxxxxx.japanwest.cloudapp.azure.com sample app ... https://xxxxxxxxx.japanwest.cloudapp.azure.com/sample-app1 (2) Gitea セットアップ
※ Gitea&DroneでCI/CD環境構築#zf9f5c8d を参照。 (3) Droneコンテナ再作成 docker-compose stop && docker-compose up --build -d (4) Drone の URL にアクセスしてサンプルアプリ用のリポジトリをActivate サンプルアプリの作成 †上記で作成したサンプルアプリ用のリポジトリに以下のリソースを commit、push して Drone のパイプラインが正常に実行された事を確認後に、sample app の URLにアクセスして画面が表示( version 1 )されたらOK。 FROM nginx COPY index.html /usr/share/nginx/html/index.html EXPOSE 80 version: "3" services: sample-app1: image: ${REGISTRY_NAME}/sample-app1:latest hostname: sample-app1 container_name: sample-app1 #ports: # - "8000:80" networks: default: external: name: my_network <!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> </head> <body> <h1>Sample App1!</h1> <div>version 1.</div> </body> </html> kind: pipeline type: docker name: default steps: - name: "build and push to registry" image: docker/compose volumes: - name: dockersock path: /var/run/docker.sock - name: containers path: /tmp/docker_container commands: - "nowdate=`date +%Y%m%d_%H%M%S`" - "appname=sample-app1" - "cat /tmp/docker_container/registry-password | docker login ${REGISTRY_NAME} --username ${REGISTRY_USER} --password-stdin" - "docker build -t $appname ." - "docker tag $appname $REGISTRY_NAME/$appname:latest" - "docker tag $appname $REGISTRY_NAME/$appname:$nowdate" - "docker push $REGISTRY_NAME/$appname:latest" - "docker push $REGISTRY_NAME/$appname:$nowdate" when: branch: - master - name: "docker pull and restart" image: docker/compose volumes: - name: dockersock path: /var/run/docker.sock - name: containers path: /tmp/docker_container commands: - "appname=sample-app1" - "cat /tmp/docker_container/registry-password | docker login ${REGISTRY_NAME} --username ${REGISTRY_USER} --password-stdin" - "if [ `docker ps | grep $appname | wc -l` != \"0\" ]; then docker stop $appname ; fi" - "if [ `docker ps -a | grep $appname | wc -l` != \"0\" ]; then docker rm $appname ; fi" - "if [ `docker images | grep ${REGISTRY_NAME}/${appname}:latest | wc -l` != \"0\" ]; then docker rmi ${REGISTRY_NAME}/${appname}:latest; fi" - "docker-compose up --build -d" when: branch: - master volumes: - name: dockersock host: path: /var/run/docker.sock - name: containers host: path: /tmp/docker_container |