{"id":224,"date":"2026-09-25T12:00:00","date_gmt":"2026-09-25T12:00:00","guid":{"rendered":"https:\/\/konteynerium.com\/?p=224"},"modified":"2026-10-06T11:34:00","modified_gmt":"2026-10-06T11:34:00","slug":"terraform-ile-altyapiyi-kodlama-infrastructure-as-code","status":"publish","type":"post","link":"https:\/\/konteynerium.com\/index.php\/2026\/09\/25\/terraform-ile-altyapiyi-kodlama-infrastructure-as-code\/","title":{"rendered":"Terraform ile Altyap\u0131y\u0131 Kodlama (Infrastructure as Code)"},"content":{"rendered":"<p>Ansible sunucular\u0131n <em>i\u00e7ini<\/em> yap\u0131land\u0131r\u0131r \u2014 paketler, kullan\u0131c\u0131lar, container&#8217;lar. Peki o sunucunun kendisi (bir bulut sa\u011flay\u0131c\u0131da bir sanal makine, a\u011f, g\u00fcvenlik grubu) nereden geliyor? Genellikle bulut sa\u011flay\u0131c\u0131n\u0131n web konsolundan elle t\u0131klanarak olu\u015fturuluyor \u2014 ki bu da t\u0131pk\u0131 elle sunucu yap\u0131land\u0131rmak gibi, tutars\u0131z ve tekrarlanamaz bir s\u00fcre\u00e7tir. <strong>Terraform<\/strong>, altyap\u0131n\u0131n kendisini de (Infrastructure as Code \u2014 IaC) kod olarak tan\u0131mlaman\u0131z\u0131 sa\u011flar.<\/p>\n<h2>Infrastructure as Code nedir, neden \u00f6nemli?<\/h2>\n<p>IaC, sunucular\u0131, a\u011flar\u0131, veritabanlar\u0131n\u0131 ve di\u011fer altyap\u0131 kaynaklar\u0131n\u0131 bir web konsolunda elle t\u0131klamak yerine, versiyon kontrol\u00fcne (Git&#8217;e) konabilen dosyalarla tan\u0131mlama prati\u011fidir. Faydalar\u0131 somuttur:<\/p>\n<ul>\n<li><strong>Tekrarlanabilirlik:<\/strong> Ayn\u0131 kod, &#8220;staging&#8221; ve &#8220;production&#8221; ortamlar\u0131nda birebir ayn\u0131 altyap\u0131y\u0131 kurar \u2014 &#8220;konsolda hangi ayar\u0131 unuttum?&#8221; sorunu ortadan kalkar.<\/li>\n<li><strong>\u0130zlenebilirlik:<\/strong> Altyap\u0131daki her de\u011fi\u015fiklik bir Git commit&#8217;idir \u2014 kim, ne zaman, neden de\u011fi\u015ftirdi, tam olarak bilinir.<\/li>\n<li><strong>Felaket kurtarma:<\/strong> Bir b\u00f6lge tamamen kaybolsa bile, kodu ba\u015fka bir b\u00f6lgede \u00e7al\u0131\u015ft\u0131rarak altyap\u0131y\u0131 dakikalar i\u00e7inde yeniden kurabilirsiniz.<\/li>\n<\/ul>\n<h2>Terraform&#8217;un \u00e7al\u0131\u015fma mant\u0131\u011f\u0131<\/h2>\n<p>Terraform, HashiCorp taraf\u0131ndan geli\u015ftirilen, bulut-ba\u011f\u0131ms\u0131z (Docker, AWS, Azure, Google Cloud, Cloudflare, hatta Kubernetes i\u00e7in de) bir IaC arac\u0131d\u0131r. HCL (HashiCorp Configuration Language) adl\u0131, YAML&#8217;a benzer okunabilir bir dille kaynaklar\u0131 <strong>deklaratif<\/strong> olarak tan\u0131mlars\u0131n\u0131z: &#8220;\u015fu \u00f6zelliklerde bir sunucu olsun&#8221; dersiniz, nas\u0131l olu\u015fturulaca\u011f\u0131yla Terraform ilgilenir. D\u00f6rt temel komuttan olu\u015fan bir d\u00f6ng\u00fcyle \u00e7al\u0131\u015f\u0131r:<\/p>\n<pre><code>terraform init      # gerekli provider eklentilerini indirir\nterraform plan      # mevcut durumla istenen durum aras\u0131ndaki fark\u0131 g\u00f6sterir (dry-run)\nterraform apply     # plan\u0131 onaylay\u0131p ger\u00e7ek de\u011fi\u015fiklikleri uygular\nterraform destroy   # tan\u0131mlanan t\u00fcm kaynaklar\u0131 g\u00fcvenle kald\u0131r\u0131r<\/code><\/pre>\n<h2>En yak\u0131n \u00f6rnek: Terraform&#8217;un Docker provider&#8217;\u0131<\/h2>\n<p>Terraform&#8217;u anlaman\u0131n en h\u0131zl\u0131 yolu, zaten bildi\u011finiz Docker \u00fczerinden gitmektir \u2014 resmi <code>kreuzwerker\/docker<\/code> provider&#8217;\u0131, <code>docker run<\/code> ile yapt\u0131\u011f\u0131n\u0131z \u015feyi HCL ile tan\u0131mlaman\u0131z\u0131 sa\u011flar:<\/p>\n<pre><code># main.tf\nterraform {\n  required_providers {\n    docker = {\n      source  = \"kreuzwerker\/docker\"\n      version = \"~> 3.0\"\n    }\n  }\n}\n\nprovider \"docker\" {}\n\nresource \"docker_image\" \"nginx\" {\n  name = \"nginx:1.27-alpine\"\n}\n\nresource \"docker_network\" \"app_net\" {\n  name = \"app-network\"\n}\n\nresource \"docker_container\" \"web\" {\n  name  = \"terraform-web\"\n  image = docker_image.nginx.image_id\n  ports {\n    internal = 80\n    external = 8080\n  }\n  networks_advanced {\n    name = docker_network.app_net.name\n  }\n}<\/code><\/pre>\n<pre><code>terraform init\nterraform apply   # onay istedi\u011finde \"yes\" yaz\u0131n<\/code><\/pre>\n<p>Bu birka\u00e7 sat\u0131r, bir imaj\u0131 \u00e7eker, bir a\u011f olu\u015fturur ve bu a\u011fa ba\u011fl\u0131 bir container&#8217;\u0131 8080 portundan yay\u0131nlayarak ba\u015flat\u0131r \u2014 <code>docker network create<\/code> + <code>docker run<\/code>&#8216;un deklaratif kar\u015f\u0131l\u0131\u011f\u0131. Fark \u015furada: bu tan\u0131m\u0131 Git&#8217;e commit edersiniz, tekrar <code>terraform apply<\/code> \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131n\u0131zda Terraform sadece <em>fark\u0131<\/em> uygular; container zaten do\u011fru haldeyse hi\u00e7bir \u015fey de\u011fi\u015fmez.<\/p>\n<h2>State (durum) dosyas\u0131: Terraform&#8217;un haf\u0131zas\u0131<\/h2>\n<p><code>terraform apply<\/code> her \u00e7al\u0131\u015ft\u0131\u011f\u0131nda, Terraform olu\u015fturdu\u011fu kaynaklar\u0131n g\u00fcncel halini <code>terraform.tfstate<\/code> adl\u0131 bir dosyaya kaydeder. Bir sonraki <code>plan<\/code>\/<code>apply<\/code> \u00e7al\u0131\u015ft\u0131\u011f\u0131nda, kodunuzdaki tan\u0131m\u0131 bu state dosyas\u0131yla kar\u015f\u0131la\u015ft\u0131r\u0131p sadece gereken fark\u0131 uygular. Ekiple \u00e7al\u0131\u015f\u0131rken bu dosyay\u0131 Git&#8217;e commit etmek yerine, birden fazla ki\u015finin ayn\u0131 anda g\u00fcvenle \u00e7al\u0131\u015fabilmesi i\u00e7in genellikle uzak bir <strong>remote backend<\/strong>&#8216;de (AWS S3 + DynamoDB lock, Terraform Cloud gibi) saklan\u0131r:<\/p>\n<pre><code>terraform {\n  backend \"s3\" {\n    bucket = \"sirketim-terraform-state\"\n    key    = \"prod\/terraform.tfstate\"\n    region = \"eu-central-1\"\n  }\n}<\/code><\/pre>\n<div class=\"callout\">\n  <span class=\"glyph\">i<\/span><\/p>\n<p><code>terraform.tfstate<\/code> dosyas\u0131 kaynaklar\u0131n\u0131z\u0131n (bazen parola gibi hassas de\u011ferler i\u00e7eren) tam bir haritas\u0131n\u0131 tutar. Bu dosyay\u0131 asla genel bir Git reposuna commit etmeyin \u2014 <code>.gitignore<\/code>&#8216;a ekleyin ve remote backend kullan\u0131n.<\/p>\n<\/div>\n<h2>Ger\u00e7ek\u00e7i \u00f6rnek: Docker \u00e7al\u0131\u015ft\u0131racak bir bulut sunucusu olu\u015fturmak<\/h2>\n<p>As\u0131l g\u00fc\u00e7, bulut sa\u011flay\u0131c\u0131larla birle\u015fti\u011finde ortaya \u00e7\u0131kar. \u00d6rne\u011fin AWS&#8217;de Docker&#8217;\u0131n kurulu gelece\u011fi bir EC2 sunucusunu tan\u0131mlamak:<\/p>\n<pre><code>provider \"aws\" {\n  region = \"eu-central-1\"\n}\n\nresource \"aws_instance\" \"docker_host\" {\n  ami           = \"ami-0c55b159cbfafe1f0\"   # Ubuntu 24.04 LTS\n  instance_type = \"t3.small\"\n\n  user_data = <<-EOF\n    #!\/bin\/bash\n    curl -fsSL https:\/\/get.docker.com | sh\n  EOF\n\n  tags = {\n    Name = \"docker-host-prod\"\n  }\n}\n\noutput \"sunucu_ip\" {\n  value = aws_instance.docker_host.public_ip\n}<\/code><\/pre>\n<p><code>user_data<\/code>, sunucu ilk a\u00e7\u0131ld\u0131\u011f\u0131nda bir kerelik \u00e7al\u0131\u015fan bir ba\u015flang\u0131\u00e7 beti\u011fidir \u2014 burada Docker'\u0131 otomatik kurar. Daha kapsaml\u0131 bir kurulum (paket g\u00fcncellemeleri, kullan\u0131c\u0131 y\u00f6netimi, birden fazla sunucu) i\u00e7in genellikle bu noktadan sonra devreye Ansible girer: Terraform sunucuyu <em>olu\u015fturur<\/em>, Ansible onu <em>yap\u0131land\u0131r\u0131r<\/em>.<\/p>\n<h2>De\u011fi\u015fkenler ve mod\u00fcller: kodu yeniden kullan\u0131labilir k\u0131lmak<\/h2>\n<pre><code># variables.tf\nvariable \"environment\" {\n  description = \"Ortam ad\u0131 (staging \/ production)\"\n  type        = string\n}\n\nvariable \"instance_type\" {\n  default = \"t3.small\"\n}\n\n# main.tf i\u00e7inde kullan\u0131m\nresource \"aws_instance\" \"docker_host\" {\n  instance_type = var.instance_type\n  tags = { Environment = var.environment }\n}<\/code><\/pre>\n<pre><code># staging ve production i\u00e7in ayn\u0131 kodu farkl\u0131 de\u011ferlerle \u00e7al\u0131\u015ft\u0131r\u0131n\nterraform apply -var=\"environment=staging\" -var=\"instance_type=t3.micro\"\nterraform apply -var=\"environment=production\" -var=\"instance_type=t3.large\"<\/code><\/pre>\n<p>Tekrarlanan altyap\u0131 par\u00e7alar\u0131 (\u00f6rne\u011fin \"standart bir web sunucusu + g\u00fcvenlik grubu\") bir <strong>mod\u00fcl<\/strong> haline getirilip, t\u0131pk\u0131 bir fonksiyon gibi farkl\u0131 projelerde tekrar tekrar \u00e7a\u011fr\u0131labilir.<\/p>\n<h2>Terraform ve Ansible: rakip de\u011fil, tamamlay\u0131c\u0131<\/h2>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>Terraform<\/th>\n<th>Ansible<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>G\u00f6revi<\/td>\n<td>Altyap\u0131y\u0131 <strong>olu\u015fturur<\/strong> (provisioning)<\/td>\n<td>Var olan sunucuyu <strong>yap\u0131land\u0131r\u0131r<\/strong> (configuration)<\/td>\n<\/tr>\n<tr>\n<td>Odak<\/td>\n<td>\"\u015eu kaynaklar var olsun\" (sunucu, a\u011f, veritaban\u0131)<\/td>\n<td>\"Sunucunun i\u00e7i \u015f\u00f6yle olsun\" (paketler, kullan\u0131c\u0131lar, dosyalar)<\/td>\n<\/tr>\n<tr>\n<td>Durum takibi<\/td>\n<td>State dosyas\u0131yla a\u00e7\u0131k \u015fekilde takip eder<\/td>\n<td>Durum tutmaz, her \u00e7al\u0131\u015ft\u0131rmada mevcut durumu kontrol eder<\/td>\n<\/tr>\n<tr>\n<td>Tipik birliktelik<\/td>\n<td colspan=\"2\">Terraform sunucuyu aya\u011fa kald\u0131r\u0131r \u2192 Ansible (veya bir <code>user_data<\/code> beti\u011fi) onu yap\u0131land\u0131r\u0131r \u2192 Docker\/Kubernetes uygulamay\u0131 \u00e7al\u0131\u015ft\u0131r\u0131r<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Art\u0131k altyap\u0131n\u0131n tamam\u0131 \u2014 sunucudan container'a kadar \u2014 kod olarak tan\u0131ml\u0131 ve tekrarlanabilir durumda. Bu kadar \u00e7ok hareketli par\u00e7ay\u0131 (Terraform, Ansible, Docker, CI\/CD) production'da g\u00fcvenle i\u015fletmenin son aya\u011f\u0131, her \u015feyin sa\u011fl\u0131kl\u0131 \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 s\u00fcrekli g\u00f6rebilmek \u2014 bunu bir sonraki yaz\u0131da, Elastic Stack ile log analizi ba\u015fl\u0131\u011f\u0131 alt\u0131nda derinle\u015ftiriyoruz.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Terraform&#8217;un Docker provider&#8217;\u0131yla container\/a\u011f olu\u015fturmaktan bulutta bir sunucu provizyonlamaya, state dosyas\u0131ndan de\u011fi\u015fken ve mod\u00fcllere kadar Infrastructure as Code&#8217;u pratik \u00f6rneklerle anlat\u0131yoruz.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"seviye":[9],"class_list":["post-224","post","type-post","status-publish","format-standard","hentry","category-production-uygulamalar","seviye-ileri"],"_links":{"self":[{"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/posts\/224","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/comments?post=224"}],"version-history":[{"count":1,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/posts\/224\/revisions"}],"predecessor-version":[{"id":583,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/posts\/224\/revisions\/583"}],"wp:attachment":[{"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/media?parent=224"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/categories?post=224"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/tags?post=224"},{"taxonomy":"seviye","embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/seviye?post=224"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}