Öğretici: Jenkins, GitHub ve Docker ile azure'da bir Linux sanal makinesi üzerinde geliştirme altyapısı oluşturmaTutorial: Create a development infrastructure on a Linux VM in Azure with Jenkins, GitHub, and Docker

Uygulama geliştirme sürecinin derleme ve test aşamasını otomatikleştirmek için bir sürekli tümleştirme ve dağıtım (CI/CD) işlem hattı kullanabilirsiniz.To automate the build and test phase of application development, you can use a continuous integration and deployment (CI/CD) pipeline. Bu öğreticide, aşağıdakileri öğrenerek bir Azure sanal makinesinde CI/CD işlem hattı oluşturursunuz:In this tutorial, you create a CI/CD pipeline on an Azure VM including how to:

  • Jenkins sanal makinesi oluşturmaCreate a Jenkins VM
  • Jenkins’i yükleme ve yapılandırmaInstall and configure Jenkins
  • GitHub ile Jenkins arasında web kancası tümleştirmesi oluşturmaCreate webhook integration between GitHub and Jenkins
  • GitHub işlemelerinden Jenkins derleme işleri oluşturma ve tetiklemeCreate and trigger Jenkins build jobs from GitHub commits
  • Uygulamanız için bir Docker görüntüsü oluşturmaCreate a Docker image for your app
  • GitHub işlemelerinin yeni Docker görüntüsü oluşturduğunu ve çalışmakta olan uygulamayı güncelleştirdiğini doğrulamaVerify GitHub commits build new Docker image and updates running app

Azure Cloud Shell kullanmaUse Azure Cloud Shell

Azure, Azure Cloud Shell, tarayıcınız üzerinden kullanabileceğiniz bir etkileşimli Kabuk ortamını barındırır.Azure hosts Azure Cloud Shell, an interactive shell environment that you can use through your browser. Cloud Shell'i ya da kullanmanıza imkan tanır bash veya PowerShell Azure hizmetleriyle çalışmak için.Cloud Shell lets you use either bash or PowerShell to work with Azure services. Cloud Shell önceden yüklenmiş komutları, yerel ortamınızda herhangi bir yükleme gerekmeden bu makaledeki kodu çalıştırmak için kullanabilirsiniz.You can use the Cloud Shell pre-installed commands to run the code in this article without having to install anything on your local environment.

Azure Cloud Shell'i başlatmak için:To launch Azure Cloud Shell:

SeçenekOption Örnek/bağlantıExample/Link
Kod bloğunun sağ üst köşesindeki Deneyin’i seçin.Select Try It in the upper-right corner of a code block. Seçme deneyin kod Cloud Shell için otomatik olarak kopyalamaz.Selecting Try It doesn't automatically copy the code to Cloud Shell. Örneği Azure Cloud Shell için deneyin
Git https://shell.azure.com veya Cloud Shell'i Başlat Cloud Shell, tarayıcınızda açmak için düğmeyi.Go to https://shell.azure.com or select the Launch Cloud Shell button to open Cloud Shell in your browser. <a href="https://shell.azure.com" title="Azure Cloud Shell'i Başlat
Seçin Cloud Shell düğmesine sağ üst menü çubuğundaki Azure portalında.Select the Cloud Shell button on the top-right menu bar in the Azure portal. Azure portaldaki Cloud Shell düğmesi

Bu makalede Azure Cloud shell'de kod çalıştırmak için:To run the code in this article in Azure Cloud Shell:

  1. Cloud Shell'i başlatın.Launch Cloud Shell.
  2. Seçin kopyalama kodu kopyalamak için bir kod bloğu üzerinde düğmesi.Select the Copy button on a code block to copy the code.
  3. Cloud Shell oturumla kodu yapıştırın Ctrl+Shift+V Windows ve Linux'ta veya Cmd + Shift+V macOS üzerinde.Paste the code into the Cloud Shell session with Ctrl+Shift+V on Windows and Linux, or Cmd+Shift+V on macOS.
  4. Tuşuna Enter kodu çalıştırmak için.Press Enter to run the code.

CLI'yi yerel olarak yükleyip kullanmayı tercih ederseniz bu öğretici için Azure CLI 2.0.30 veya sonraki bir sürümünü çalıştırmanız gerekir.If you choose to install and use the CLI locally, this tutorial requires that you are running the Azure CLI version 2.0.30 or later. Sürümü bulmak için az --version komutunu çalıştırın.Run az --version to find the version. Yükleme veya yükseltme yapmanız gerekiyorsa bkz. Azure CLI'yı yükleme.If you need to install or upgrade, see Install Azure CLI.

Jenkins örneği oluşturmaCreate Jenkins instance

İlk önyüklemede Linux sanal makinelerini özelleştirme konulu önceki bir öğreticide, cloud-init ile VM özelleştirmeyi nasıl otomatikleştirebileceğinizi öğrendiniz.In a previous tutorial on How to customize a Linux virtual machine on first boot, you learned how to automate VM customization with cloud-init. Bu öğreticide, bir VM’ye Jenkins ve Docker yüklemek için cloud-init dosyası kullanılır.This tutorial uses a cloud-init file to install Jenkins and Docker on a VM. Jenkins, sürekli tümleştirme (CI) ve sürekli teslimi (CD) etkinleştirmek için Azure ile sorunsuz bir şekilde tümleştirilen popüler bir açık kaynak otomasyon sunucusudur.Jenkins is a popular open-source automation server that integrates seamlessly with Azure to enable continuous integration (CI) and continuous delivery (CD). Jenkins kullanmayla ilgili diğer öğreticiler için bkz. Azure’da Jenkins merkezi.For more tutorials on how to use Jenkins, see the Jenkins in Azure hub.

Geçerli kabuğunuzda cloud-init-jenkins.txt adlı bir dosya oluşturup aşağıdaki yapılandırmayı yapıştırın.In your current shell, create a file named cloud-init-jenkins.txt and paste the following configuration. Örneğin, dosyayı yerel makinenizde değil Cloud Shell’de oluşturun.For example, create the file in the Cloud Shell not on your local machine. Dosyayı oluşturmak ve kullanılabilir düzenleyicilerin listesini görmek için sensible-editor cloud-init-jenkins.txt adını girin.Enter sensible-editor cloud-init-jenkins.txt to create the file and see a list of available editors. Başta birinci satır olmak üzere cloud-init dosyasının tamamının doğru bir şekilde kopyalandığından emin olun:Make sure that the whole cloud-init file is copied correctly, especially the first line:

#cloud-config
package_upgrade: true
write_files:
  - path: /etc/systemd/system/docker.service.d/docker.conf
    content: |
      [Service]
        ExecStart=
        ExecStart=/usr/bin/dockerd
  - path: /etc/docker/daemon.json
    content: |
      {
        "hosts": ["fd://","tcp://127.0.0.1:2375"]
      }
runcmd:
  - apt install openjdk-8-jre-headless -y
  - wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -
  - sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
  - apt-get update && apt-get install jenkins -y
  - curl -sSL https://get.docker.com/ | sh
  - usermod -aG docker azureuser
  - usermod -aG docker jenkins
  - service jenkins restart

VM oluşturabilmek için önce az group create ile bir kaynak grubu oluşturun.Before you can create a VM, create a resource group with az group create. Aşağıdaki örnekte, eastus konumunda myResourceGroupJenkins adlı bir kaynak grubu oluşturulur:The following example creates a resource group named myResourceGroupJenkins in the eastus location:

az group create --name myResourceGroupJenkins --location eastus

Şimdi az vm create ile bir VM oluşturun.Now create a VM with az vm create. --custom-data parametresini kullanarak cloud-init yapılandırma dosyanızı geçirin.Use the --custom-data parameter to pass in your cloud-init config file. Dosyayı geçerli çalışma dizininizin dışına kaydettiyseniz cloud-init-jenkins.txt dosyasının tam yolunu belirtin.Provide the full path to cloud-init-jenkins.txt if you saved the file outside of your present working directory.

az vm create --resource-group myResourceGroupJenkins \
    --name myVM \
    --image UbuntuLTS \
    --admin-username azureuser \
    --generate-ssh-keys \
    --custom-data cloud-init-jenkins.txt

Sanal makinenin oluşturulup yapılandırılması birkaç dakika sürer.It takes a few minutes for the VM to be created and configured.

VM’nize web trafiğinin ulaşmasına izin vermek için az vm open-port komutunu kullanarak Jenkins trafiği için 8080 bağlantı noktasını, Node.js uygulaması için örnek uygulama çalıştırmaya yönelik 1337 bağlantı noktasını açın:To allow web traffic to reach your VM, use az vm open-port to open port 8080 for Jenkins traffic and port 1337 for the Node.js app that is used to run a sample app:

az vm open-port --resource-group myResourceGroupJenkins --name myVM --port 8080 --priority 1001
az vm open-port --resource-group myResourceGroupJenkins --name myVM --port 1337 --priority 1002

Jenkins’i yapılandırmaConfigure Jenkins

Jenkins örneğinize erişmek için VM’nizin genel IP adresini edinin:To access your Jenkins instance, obtain the public IP address of your VM:

az vm show --resource-group myResourceGroupJenkins --name myVM -d --query [publicIps] --o tsv

Güvenlik nedeniyle, Jenkins yüklemesini başlatmak için VM’nizde bir metin dosyasında saklanan ilk yönetici parolasını girmeniz gerekir.For security purposes, you need to enter the initial admin password that is stored in a text file on your VM to start the Jenkins install. Önceki adımda edinilen genel IP adresini kullanarak VM’niz ile SSH bağlantısı kurun:Use the public IP address obtained in the previous step to SSH to your VM:

ssh azureuser@<publicIps>

Jenkins kullanarak çalıştığını doğrulamak service komutu:Verify Jenkins is running using the service command:

$ service jenkins status
● jenkins.service - LSB: Start Jenkins at boot time
   Loaded: loaded (/etc/init.d/jenkins; generated)
   Active: active (exited) since Tue 2019-02-12 16:16:11 UTC; 55s ago
     Docs: man:systemd-sysv-generator(8)
    Tasks: 0 (limit: 4103)
   CGroup: /system.slice/jenkins.service

Feb 12 16:16:10 myVM systemd[1]: Starting LSB: Start Jenkins at boot time...
...

Jenkins yüklemenizin initialAdminPassword değerini görüntüleyin ve kopyalayın:View the initialAdminPassword for your Jenkins install and copy it:

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

Dosya henüz kullanılamıyorsa cloud-init tarafından Jenkins ve Docker yüklemesinin tamamlanması için birkaç dakika daha bekleyin.If the file isn't available yet, wait a couple more minutes for cloud-init to complete the Jenkins and Docker install.

Şimdi bir web tarayıcısı açıp http://<publicIps>:8080 adresine gidin.Now open a web browser and go to http://<publicIps>:8080. Aşağıdaki adımları uygulayarak ilk Jenkins kurulumunu tamamlayın:Complete the initial Jenkins setup as follows:

  • Yüklenecek eklentileri seçin seçeneğini belirleyinChoose Select plugins to install
  • Üstteki metin kutusundan GitHub araması yapın.Search for GitHub in the text box across the top. GitHub kutusunu işaretleyin ve Yükle’yi seçinCheck the box for GitHub, then select Install
  • İlk yönetici kullanıcıyı oluşturun.Create the first admin user. admin gibi bir kullanıcı adı girin ve sonra kendi güvenli parolanızı belirtin.Enter a username, such as admin, then provide your own secure password. Son olarak, bir tam ad ve e-posta adresi yazın.Finally, type a full name and e-mail address.
  • Kaydet ve Bitir’i seçinSelect Save and Finish
  • Jenkins hazır olduktan sonra Jenkins kullanmaya başla’yı seçinOnce Jenkins is ready, select Start using Jenkins
    • Jenkins kullanmaya başladığınızda web tarayıcınız boş bir sayfa görüntülerse, Jenkins hizmetini yeniden başlatın.If your web browser displays a blank page when you start using Jenkins, restart the Jenkins service. SSH oturumundan sudo service jenkins restart yazın ve web tarayıcınızı yenileyin.From your SSH session, type sudo service jenkins restart, then refresh you web browser.
  • Gerekirse, Jenkins için kullanıcı adı ve oluşturduğunuz parola ile oturum açın.If needed, log in to Jenkins with the username and password you created.

GitHub web kancası oluşturmaCreate GitHub webhook

GitHub tümleştirmesini yapılandırmak için Azure örnek deposundan Node.js Hello World örnek uygulamasını açın.To configure the integration with GitHub, open the Node.js Hello World sample app from the Azure samples repo. Depo için GitHub hesabınızda çatal oluşturmak üzere sağ üst köşedeki Fork (Çatal Oluştur) düğmesini seçin.To fork the repo to your own GitHub account, select the Fork button in the top right-hand corner.

Oluşturduğunuz çatalın içinde bir web kancası oluşturun:Create a webhook inside the fork you created:

  • Seçin ayarları, ardından Web kancaları sol taraftaki.Select Settings, then select Webhooks on the left-hand side.
  • Seçin Web kancası Ekle, enter Jenkins filtre kutusuna.Choose Add webhook, then enter Jenkins in filter box.
  • İçin yük URL'si, girin http://<publicIps>:8080/github-webhook/.For the Payload URL, enter http://<publicIps>:8080/github-webhook/. Sondaki / karakterini eklemeyi unutmayınMake sure you include the trailing /
  • İçin içerik türüseçin application/x-www-form-urlencoded işlemek.For Content type, select application/x-www-form-urlencoded.
  • İçin hangi olayların bu Web kancası tetiklemenin ister misiniz? seçin yalnızca anında iletme olay.For Which events would you like to trigger this webhook?, select Just the push event.
  • Ayarlama etkin için işaretlenmiş.Set Active to checked.
  • Tıklayın Web kancası Ekle.Click Add webhook.

GitHub web kancasını çatalı oluşturulan deponuza ekleyin

Jenkins işi oluşturmaCreate Jenkins job

Jenkins’in GitHub’daki kod işleme gibi olaylara yanıt vermesini sağlamak için bir Jenkins işi oluşturun.To have Jenkins respond to an event in GitHub such as committing code, create a Jenkins job. Kendi GitHub çatalınız için URL’leri kullanın.Use the URLs for your own GitHub fork.

Jenkins web sitenizde, giriş sayfasından Yeni iş oluştur’u seçin:In your Jenkins website, select Create new jobs from the home page:

  • İş adı olarak HelloWorld adını girin.Enter HelloWorld as job name. Serbest tarzda proje’yi seçip Tamam’ı seçin.Choose Freestyle project, then select OK.
  • Genel bölümünden GitHub projesi’ni seçip çatalı oluşturulan deponuzun URL’sini https://github.com/cynthn/nodejs-docs-hello-world şeklinde girinUnder the General section, select GitHub project and enter your forked repo URL, such as https://github.com/cynthn/nodejs-docs-hello-world
  • Kaynak kodu yönetimi bölümünden Git’i seçip çatalı oluşturulan deponuzun .git URL’sini https://github.com/cynthn/nodejs-docs-hello-world.git şeklinde girinUnder the Source code management section, select Git, enter your forked repo .git URL, such as https://github.com/cynthn/nodejs-docs-hello-world.git
  • Derleme Tetikleyicileri bölümünden GITScm yoklaması için GitHub kanca tetikleyicisi’ni seçin.Under the Build Triggers section, select GitHub hook trigger for GITscm polling.
  • Derleme bölümünden Derleme adımı ekle’yi seçin.Under the Build section, choose Add build step. Kabuğu yürüt’ü seçin ve komut penceresine echo "Test" ifadesini girin.Select Execute shell, then enter echo "Test" in the command window.
  • İşler penceresinin en altından Kaydet’i belirleyin.Select Save at the bottom of the jobs window.

GitHub tümleştirmesini test etmeTest GitHub integration

Jenkins ile GitHub tümleştirmesini test etmek için çatalınızda bir değişiklik işleyin.To test the GitHub integration with Jenkins, commit a change in your fork.

GitHub web kullanıcı arabirimine dönerek çatalı oluşturulan deponuzu seçip index.js dosyasını seçin.Back in GitHub web UI, select your forked repo, and then select the index.js file. Kalem simgesini seçerek bu dosyayı 6. satırda şu yazacak şekilde düzenleyin:Select the pencil icon to edit this file so line 6 reads:

response.end("Hello World!");

Değişikliklerinizi işlemek için alttaki Değişiklikleri işle düğmesini seçin.To commit your changes, select the Commit changes button at the bottom.

Jenkins’de işinizin bulunduğu sayfanın sol alt köşesindeki Derleme geçmişi bölümünün altında yeni bir derleme başlar.In Jenkins, a new build starts under the Build history section of the bottom left-hand corner of your job page. Derleme numarası bağlantısını seçip sol taraftan Konsol çıktısı’nı seçin.Choose the build number link and select Console output on the left-hand side. Kodunuz GitHub’dan çekilirken ve derleme eylemi tarafından konsola çıktı olarak Test mesajı iletilirken Jenkins’in uyguladığı adımları görebilirsiniz.You can view the steps Jenkins takes as your code is pulled from GitHub and the build action outputs the message Test to the console. GitHub’da her işleme gerçekleştirildiğinde web kancası bu şekilde Jenkins’e ulaşır ve yeni bir derleme tetikler.Each time a commit is made in GitHub, the webhook reaches out to Jenkins and triggers a new build in this way.

Docker derleme görüntüsünü tanımlamaDefine Docker build image

Node.js uygulamasının GitHub işlemelerinize bağlı olarak çalışmasını görmek için uygulamayı çalıştırmaya yönelik bir Docker görüntüsü oluşturalım.To see the Node.js app running based on your GitHub commits, lets build a Docker image to run the app. Görüntü, uygulamayı çalıştıran kapsayıcının nasıl yapılandırılacağını tanımlayan bir Dockerfile’dan oluşturulur.The image is built from a Dockerfile that defines how to configure the container that runs the app.

VM’niz ile kurulan SSH bağlantısından, önceki adımlardan birinde oluşturduğunuz işin adını verdiğiniz Jenkins çalışma dizinine geçin.From the SSH connection to your VM, change to the Jenkins workspace directory named after the job you created in a previous step. Bu örnekte HelloWorld olarak adlandırılmıştı.In this example, that was named HelloWorld.

cd /var/lib/jenkins/workspace/HelloWorld

sudo sensible-editor Dockerfile ile bu çalışma alanı dizininde bir dosya oluşturun ve aşağıdaki içeriği yapıştırın.Create a file in this workspace directory with sudo sensible-editor Dockerfile and paste the following contents. Başta birinci satır olmak üzere Dockerfile’ın tamamının doğru bir şekilde kopyalandığından emin olun:Make sure that the whole Dockerfile is copied correctly, especially the first line:

FROM node:alpine

EXPOSE 1337

WORKDIR /var/www
COPY package.json /var/www/
RUN npm install
COPY index.js /var/www/

Bu Dockerfile, Alpine Linux kullanan temel Node.js görüntüsünü kullanır, Hello World uygulamasının üzerinde çalıştığı 1337 bağlantı noktasını kullanıma açar ve sonra uygulama dosyalarını kopyalayıp uygulamayı başlatır.This Dockerfile uses the base Node.js image using Alpine Linux, exposes port 1337 that the Hello World app runs on, then copies the app files and initializes it.

Jenkins derleme kuralları oluşturmaCreate Jenkins build rules

Önceki adımlardan birinde, çıktı olarak konsola mesaj gönderen temel bir Jenkins derleme kuralı oluşturmuştunuz.In a previous step, you created a basic Jenkins build rule that output a message to the console. Dockerfile’ımızı kullanmak için derleme adımını oluşturalım ve uygulamayı çalıştıralım.Lets create the build step to use our Dockerfile and run the app.

Jenkins örneğine dönerek önceki adımlardan birinde oluşturduğunuz işi seçin.Back in your Jenkins instance, select the job you created in a previous step. Sol taraftan Yapılandır’ı seçin ve aşağı kaydırarak Derleme bölümüne gidin:Select Configure on the left-hand side and scroll down to the Build section:

  • Mevcut echo "Test" derleme adımınızı kaldırın.Remove your existing echo "Test" build step. Mevcut derleme adımı kutusunun sağ üst köşesindeki kırmızı çarpı işaretini seçin.Select the red cross on the top right-hand corner of the existing build step box.

  • Derleme adımı ekle’yi seçip Kabuğu yürüt’ü seçinChoose Add build step, then select Execute shell

  • Komut kutusuna aşağıdaki Docker komutlarını girip Kaydet’i seçin:In the Command box, enter the following Docker commands, then select Save:

    docker build --tag helloworld:$BUILD_NUMBER .
    docker stop helloworld && docker rm helloworld
    docker run --name helloworld -p 1337:1337 helloworld:$BUILD_NUMBER node /var/www/index.js &
    

Docker derleme adımları bir görüntü oluşturur ve görüntülerin geçmişini tutabilmeniz için bunu Jenkins derleme numarasıyla etiketler.The Docker build steps create an image and tag it with the Jenkins build number so you can maintain a history of images. Uygulamayı çalıştıran mevcut kapsayıcılar varsa bunlar durdurulup kaldırılır.Any existing containers running the app are stopped and then removed. Daha sonra, yeni bir kapsayıcı görüntüyü kullanmaya başlar ve GitHub’daki en son işlemeleri temel alarak Node.js uygulamanızı çalıştırır.A new container is then started using the image and runs your Node.js app based on the latest commits in GitHub.

İşlem hattınızı test etmeTest your pipeline

İşlem hattının tamamını iş başında görmek için çatalı oluşturulan GitHub deponuzdaki index.js dosyasını yeniden düzenleyin ve Değişikliği işle’yi seçin.To see the whole pipeline in action, edit the index.js file in your forked GitHub repo again and select Commit change. Jenkins’de GitHub’a yönelik web kancasını temel alan yeni bir iş başlatılır.A new job starts in Jenkins based on the webhook for GitHub. Docker görüntüsünün oluşturulup uygulamanızın yeni bir kapsayıcıda başlatılması birkaç saniye alır.It takes a few seconds to create the Docker image and start your app in a new container.

Gerekirse VM’nizin genel IP adresini yeniden edinin:If needed, obtain the public IP address of your VM again:

az vm show --resource-group myResourceGroupJenkins --name myVM -d --query [publicIps] --o tsv

Bir web tarayıcısı açıp http://<publicIps>:1337 adresini girin.Open a web browser and enter http://<publicIps>:1337. Node.js uygulamanız görüntülenir ve GitHub çatalınızdaki son işlemeleri aşağıdaki gibi gösterir:Your Node.js app is displayed and reflects the latest commits in your GitHub fork as follows:

Node.js uygulaması çalıştırma

Şimdi GitHub’daki index.js dosyasında bir düzenleme işlemi daha yapın ve değişikliği işleyin.Now make another edit to the index.js file in GitHub and commit the change. Jenkins’deki işin tamamlanması için birkaç saniye bekleyin, sonra uygulamanızın güncelleştirilen sürümünün aşağıdaki gibi yeni bir kapsayıcıda çalıştığını görmek için web tarayıcınızı yenileyin:Wait a few seconds for the job to complete in Jenkins, then refresh your web browser to see the updated version of your app running in a new container as follows:

Başka bir GitHub işlemesinden sonra Node.js uygulamasını çalıştırma

Sonraki adımlarNext steps

Bu öğreticide, GitHub’ı her kod işlemesinde bir Jenkins derleme işi çalıştıracak ve sonra uygulamanızı test etmek için bir Docker kapsayıcısı dağıtacak şekilde yapılandırdınız.In this tutorial, you configured GitHub to run a Jenkins build job on each code commit and then deploy a Docker container to test your app. Şunları öğrendiniz:You learned how to:

  • Jenkins sanal makinesi oluşturmaCreate a Jenkins VM
  • Jenkins’i yükleme ve yapılandırmaInstall and configure Jenkins
  • GitHub ile Jenkins arasında web kancası tümleştirmesi oluşturmaCreate webhook integration between GitHub and Jenkins
  • GitHub işlemelerinden Jenkins derleme işleri oluşturma ve tetiklemeCreate and trigger Jenkins build jobs from GitHub commits
  • Uygulamanız için bir Docker görüntüsü oluşturmaCreate a Docker image for your app
  • GitHub işlemelerinin yeni Docker görüntüsü oluşturduğunu ve çalışmakta olan uygulamayı güncelleştirdiğini doğrulamaVerify GitHub commits build new Docker image and updates running app

Jenkins’i Azure DevOps Services ile tümleştirme hakkında daha fazla bilgi edinmek için bir sonraki öğretici ilerleyin.Advance to the next tutorial to learn more about how to integrate Jenkins with Azure DevOps Services.