<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Albert Coronado</title>
    <description>The latest articles on DEV Community by Albert Coronado (@acoronadoc).</description>
    <link>https://dev.to/acoronadoc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F764225%2Fd2f37191-8d4d-486d-8e18-c5ff3b1806e5.jpg</url>
      <title>DEV Community: Albert Coronado</title>
      <link>https://dev.to/acoronadoc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/acoronadoc"/>
    <language>en</language>
    <item>
      <title>Create CI/CD pipelines en Golang</title>
      <dc:creator>Albert Coronado</dc:creator>
      <pubDate>Mon, 03 Feb 2025 16:40:47 +0000</pubDate>
      <link>https://dev.to/acoronadoc/create-cicd-pipelines-en-golang-c9k</link>
      <guid>https://dev.to/acoronadoc/create-cicd-pipelines-en-golang-c9k</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/acoronadoc/cicd" rel="noopener noreferrer"&gt;Golang CI/CD&lt;/a&gt; is a library to build and automate continuous integration and continuous delivery (CI/CD) pipelines. By leveraging Go's concurrency features, efficiency, and robust standard library, devops can create highly customizable and efficient CI/CD pipelines tailored to their specific project requirements. This allows for faster development cycles, improved code quality, and more reliable deployments.&lt;/p&gt;

&lt;p&gt;Atention! Is not just for Golang projects. You can create CICD pipelines for all languages and technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lightweight, flexible and fast.&lt;/li&gt;
&lt;li&gt;You can compile the pipeline in order to ofuscate secrets.&lt;/li&gt;
&lt;li&gt;Use concurrency, logs, functional programming and other resources of Golang.&lt;/li&gt;
&lt;li&gt;Connect to Git servers, SSH remote servers, etc.&lt;/li&gt;
&lt;li&gt;Easy to integrate with Github, Gitlab, Cloud and other tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to create a pipeline
&lt;/h2&gt;

&lt;p&gt;Create a module and install the library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go mod init gocicd-sample &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/acoronadoc/cicd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create your first pipeline(script.go):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/acoronadoc/cicd"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;repoURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"git@github.com:acoronadoc/test-repo.git"&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;repoBranch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"main"&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;repoKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"./key"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;cicd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartPipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="n"&gt;cicd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PipeWaitForCommit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repoURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repoBranch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repoKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cicd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepoPipe&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Download Commit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;"COMMITID"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

            &lt;span class="n"&gt;cicd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"-R"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"./repo"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
            &lt;span class="n"&gt;cicd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GitCloneSSH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repoURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repoBranch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"./repo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repoKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;cicd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"stop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"app1"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
            &lt;span class="n"&gt;cicd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"rm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"app1"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
            &lt;span class="n"&gt;cicd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"--name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"app1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-p"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"8080:80"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"nginx:1.27-alpine3.20"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
            &lt;span class="n"&gt;cicd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"cp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"./repo/index.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"app1:/usr/share/nginx/html/index.html"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
        &lt;span class="p"&gt;}},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have more samples &lt;a href="https://github.com/acoronadoc/cicd/tree/main/samples" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why I should start using Zig language?</title>
      <dc:creator>Albert Coronado</dc:creator>
      <pubDate>Tue, 27 Aug 2024 07:31:03 +0000</pubDate>
      <link>https://dev.to/acoronadoc/why-i-should-start-using-zig-language-1hld</link>
      <guid>https://dev.to/acoronadoc/why-i-should-start-using-zig-language-1hld</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Why I should start using Zig language? &lt;/li&gt;
&lt;li&gt;What made better than Go or Rust? &lt;/li&gt;
&lt;li&gt;How many companies are using it? &lt;/li&gt;
&lt;li&gt;Which is his "market niche"?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>zig</category>
      <category>coding</category>
    </item>
    <item>
      <title>Tutorial de Mkdocs</title>
      <dc:creator>Albert Coronado</dc:creator>
      <pubDate>Fri, 03 May 2024 14:56:30 +0000</pubDate>
      <link>https://dev.to/acoronadoc/tutorial-de-mkdocs-3c09</link>
      <guid>https://dev.to/acoronadoc/tutorial-de-mkdocs-3c09</guid>
      <description>&lt;p&gt;Tal como hemos visto en el vídeo Mkdocs es una excelente herramienta que nos permite crear sitios web estáticos fácilmente a partir de ficheros escritos en Markdown. Ideal para sites de proyectos y/o documentación.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/YGg39_zG1fk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Vamos a documentar en este artículo todos los pasos que hemos ido haciendo:&lt;/p&gt;

&lt;h2&gt;
  
  
  Creando contenedor Docker para trabajar con Python
&lt;/h2&gt;

&lt;p&gt;Mkdocs es una herramienta basada en Python(Hemos trabajado mucho en el canal/blog con este lenguaje). No es obligatorio, pero nosotros hemos creado un contenedor Docker con Python para trabajar usando el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm -it -p 8000:8000 -v .:/mkdocs python:3.9 bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Básicamente arrancamos el contenedor con el comando "run" con los parámetros: "--rm" para eliminar el contenedor una vez terminemos con el(Así no generamos basura), "-it" para añadir el modo interactivo y una pseudo tty, mapeamos el puerto 8000 con localhost y mapeamos la carpeta actual con la carpeta "/mkdocs" del contenedor.&lt;/p&gt;

&lt;p&gt;Una vez dentro del contenedor tenemos un entorno con Python operativo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalando las dependencias de Mkdocs
&lt;/h2&gt;

&lt;p&gt;Para empezar instalaremos Mkdocs y para ello podríamos hacer simplemente "pip install 'mkdocs==1.5.2'" aunque en el vídeo hemos optado por crear un fichero llamado "requirements.txt" con la dependencia dentro "mkdocs==1.5.2" y ejecutar "pip install -r requirements.txt".&lt;/p&gt;

&lt;h2&gt;
  
  
  Creando nuestro primer proyecto con mkdocs
&lt;/h2&gt;

&lt;p&gt;Un proyecto Mkdocs básicamente se construye en base a un fichero llamado "mkdocs.yml" donde configuramos todas la propiedades del proyecto como: nombre, url, páginas, theme, etc.&lt;/p&gt;

&lt;p&gt;Para no empezar con un folio en blanco hemos usado el siguiente comando para que nos creara un esqueleto de proyecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdocs new project1 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto nos ha creado una carpeta llamada "project1", el fichero de configuración "mkdocs" y una carpeta llamada "docs" con una primera página.&lt;/p&gt;

&lt;h2&gt;
  
  
  Servir la página usando el servidor web embedido de Mkdocs
&lt;/h2&gt;

&lt;p&gt;Una vez configurado nuestro site hemos visto como podemos servirlo usando un servidor embedido que trae Mkdocs con el siguiente comando(Debe ejecutarse desde la carpeta que contiene el fichero "mkdocs.yml"):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdocs serve -a 0.0.0.0:8000 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generar web estática
&lt;/h2&gt;

&lt;p&gt;Otra opción para servir nuestra web que nos ofrece Mkdocs es generar todos los ficheros estáticos(HTML, CSS y JS) para luego servirlos desde cualquier hosting. Esto lo hemos hecho con el comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdocs build 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Themes
&lt;/h2&gt;

&lt;p&gt;Hemos visto como podíamos instalar diferentes temas de apariencia para darle a nuestro site diferentes aspectos, hemos probado temas como material, terminal o gitbook entre otros. Esto se hace como se instala cualquier módulo de Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install mkdocs-gitbook
pip install mkdocs-material
pip install mkdocs-terminal 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez instalados podíamos ver nuestra web usando estos temas simplemente configurando la etiqueta "theme: &amp;lt;nombre del tema&amp;gt;" en el fichero "mkdocs.yml" o con el parámetro "-t" del comando "mkdocs".&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugins
&lt;/h2&gt;

&lt;p&gt;Finalmente, mkdocs también nos permite el uso de plugins para extender su funcionalidad. En nuestro caso hemos instalado este plugin para generar el contenido en PDF:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install mkdocs-pdf-export-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hemos configurado el fichero "mkdocs.yml" para que use el plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plugins:
    - pdf-export:
        verbose: true
        media_type: print
        enabled_if_env: ENABLE_PDF_EXPORT
        combined: true 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y con el siguiente comando hemos podido ver como se nos generaba el PDF(Incluso usando distintos temas de apariencia):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ENABLE_PDF_EXPORT=1

mkdocs build 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>mkdocs</category>
      <category>spanish</category>
      <category>devops</category>
      <category>documentation</category>
    </item>
    <item>
      <title>Despliegue y configuración de infraestructura DevOps para tus proyectos</title>
      <dc:creator>Albert Coronado</dc:creator>
      <pubDate>Thu, 18 Apr 2024 13:05:40 +0000</pubDate>
      <link>https://dev.to/acoronadoc/despliegue-y-configuracion-de-infraestructura-devops-para-tus-proyectos-bc5</link>
      <guid>https://dev.to/acoronadoc/despliegue-y-configuracion-de-infraestructura-devops-para-tus-proyectos-bc5</guid>
      <description>&lt;p&gt;En este vídeo hemos aprendido a montarnos una pipeline de despliegue DevOps real usando cantidad de tecnologías, algunas de las cuales las hemos instalado: Gitlab, Gitlab CICD, Docker hub, Kubernetes(GKE) sobre Google Cloud Platform(GCP) o Kaniko.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/UwFNsZKNg74"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Creación de un cluster sobre Google Cloud Platform(GCP)
&lt;/h2&gt;

&lt;p&gt;Este paso lo hemos realizado desde la consola de GCP en &lt;a href="https://console.cloud.google.com/" rel="noopener noreferrer"&gt;https://console.cloud.google.com/&lt;/a&gt; y es bastante visual, con lo que mejor os basáis en el vídeo.&lt;/p&gt;

&lt;p&gt;Obviamente, podríamos haber contratado el cluster a través de cualquier otro proveeros cloud como Amazon o Azure o incluso instalar Kubernetes en nuestros propios servidores con K0s, K3s o similares(Tenemos vídeos y artículos de referencia sobre el tema).&lt;/p&gt;

&lt;p&gt;Otra mejora hubiera sido contratar el servicio vía Gcloud o Terraform que nos permitía automatizar este paso. Pero esto ya es otra historia.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuración de credenciales de Docker Hub para el despliegue
&lt;/h2&gt;

&lt;p&gt;Para poder desplegar sobre Kubernetes necesitamos un "Registry", que básicamente, se trata de un repositorio donde almacenar las imágenes que vamos a desplegar. En este caso, para no liar mas el vídeo, hemos optado por usar Docker Hub, que nos permite usarlo como servicio SaaS y con su capa gratuita nos vale.&lt;/p&gt;

&lt;p&gt;Para ello hemos tenido que configurar unas credenciales y lo hemos hecho vía su interfaz web así que es mas fácil verlo en el vídeo que explicarlo en un artículo.&lt;/p&gt;

&lt;p&gt;Me guardo para otro vídeo como instalar alguna alternativa como Nexus para tener nuestro propio registry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Acceso a Google Cloud Platform(GCP) usando la imagen Docker con Cloud SDK
&lt;/h2&gt;

&lt;p&gt;Para conectarnos al Kubernetes sobre GCP hemos optado por hacerlo usando una imagen de Docker que nos provee el mismo Google. Esta imagen incluye de serie cantidad de utilidades para interactuar con GCP y Kubernetes como son: gcloud(Herramienta CLI para interactuar con GCP), bq(Utilidad para interactuar con los servicios de ingeniería de datos de GCP), gsutils(para subir fichero a GCP), kubectl, Helm, etc.&lt;/p&gt;

&lt;p&gt;Hemos arrancado el contenedor con el comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm -it -v .:/poc google/cloud-sdk:latest 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este commando básicamente arranca el contenedor habilitando el modo interactivo(parámetros -it), montando la carpeta actual en la carpeta /poc(parámetro -v .:/poc) y haciendo que se autodestruya al salir del contenedor(parámetro --rm).&lt;/p&gt;

&lt;p&gt;Una vez dentro nos hemos logueado en GCP y configurado el cliente de kubernetes(kubectl) para que use nuestro cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Login dentro de GCP
gcloud auth login

# Configuración de kubectl apuntando a nuestro cluster
gcloud container clusters get-credentials --zone "ZONA DEL CLUSTER" --project "PROYECTO DE GCP" "NOMBRE DEL CLUSTER"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Instalación de Gitlab sobre Kubernetes(GKE) sobre GCP
&lt;/h2&gt;

&lt;p&gt;Para instalar Gitlab hemos usado el siguiente manifiesto de kubernetes(gitlab.yaml):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kind: Namespace
apiVersion: v1
metadata:
  name: gitlab
  labels:
    name: gitlab-namespace
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gitlab-deployment
  namespace: gitlab
  labels:
    app: gitlab
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gitlab
  template:
    metadata:
      labels:
        app: gitlab
    spec:
      containers:
      - name: gitlab
        image: gitlab/gitlab-ce:16.7.5-ce.0
        env:
          - name: GITLAB_OMNIBUS_CONFIG
            value: "external_url 'http://gitlab-service'"
          - name: GITLAB_ROOT_PASSWORD
            value: "YoutubePlus!"
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  namespace: gitlab
  name: gitlab-service
spec:
  type: LoadBalancer
  selector:
    app: gitlab
  ports:
      - protocol: TCP
        port: 80
        targetPort: 80      
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hemos usado el siguiente comando para aplicarlo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubectl apply -f gitlab.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Instalación del Runner de Gitlab
&lt;/h2&gt;

&lt;p&gt;Los Runners de Gitlab son los encargado de ejecutar las tareas de las pipelines de Gitlab CICD y los hay de muchos tipos(locales, amazon, Docker, etc). Nosotros hemos optado por instalar una de tipo kubernetes.&lt;/p&gt;

&lt;p&gt;Los Runners se instalan a nivel de grupo, por lo que hemos necesitado primero crear un grupo de gitlab y una vez dentro, ir a la pestaña "CI / CD" y "Runners" para obtener el token necesario para instalarlo(Esto lo podríamos haber automatizado usando el API de Gitlab, por si ha alguien le interesa).&lt;/p&gt;

&lt;p&gt;Ya con nuestro token(parámetro registration-token) hemos usado el siguiente manifiesto para instalar el runner(gitlab-runner.yaml):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab-service-account-sa
  namespace: gitlab
  labels:
    app: native-app
imagePullSecrets:
  - name: registry-credentials    
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: gitlab-service-account-cr
  namespace: gitlab
  labels:
    app: native-app
rules:
  - apiGroups:
      - ''
      - apps
      - autoscaling
      - batch
      - build.openshift.io
      - image.openshift.io
      - route.openshift.io
    resources:
      - services
      - pods
      - pods/log
      - pods/exec
      - pods/attach
      - namespaces
      - replicationcontrollers
      - daemonsets.apps
      - deployments
      - replicasets
      - statefulsets
      - horizontalpodautoscalers
      - cronjobs
      - jobs
      - daemonsets
      - buildconfigs
      - builds
      - imagestreams
      - imagestreamtags
      - buildconfigs/instantiatebinary
      - routes
      - secrets
    verbs:
      - create
      - watch
      - get
      - list
      - update
      - patch
      - delete
      - deletecollection
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: gitlab-service-account-rbcr
  namespace: gitlab
roleRef:
  kind: ClusterRole
  name: gitlab-service-account-cr
  apiGroup: rbac.authorization.k8s.io
subjects:
  - kind: ServiceAccount
    name: gitlab-service-account-sa
    namespace: gitlab
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: runner-0
  namespace: gitlab
spec:
  selector:
    matchLabels:
      name: runner-pod-0
  template:
    metadata:
      namespace: gitlab
      labels:
        name: runner-pod-0
    spec:
      serviceAccount: gitlab-service-account-sa
      serviceAccountName: gitlab-service-account-sa
      containers:
      - name: pod
        image: alpinelinux/gitlab-runner:latest
        command: 
          - "/bin/sh"
          - "-c"
          - |           
            gitlab-runner register \
              --kubernetes-privileged true \
              --non-interactive \
              --run-untagged=false \
              --executor kubernetes \
              --kubernetes-pull-policy always \
              --request-concurrency 10 \
              --name 'My Runner' \
              --kubernetes-image alpine:latest \
              --kubernetes-image-pull-secrets registry-credentials \
              --kubernetes-namespace gitlab \
              --kubernetes-service-account gitlab-service-account-sa \
              --tag-list kubernetes \
              --url "http://gitlab-service/" \
              --registration-token "GR1348941zBB3FQSts6S282gMoNNC"

            cat /etc/gitlab-runner/config.toml

            gitlab-runner run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hemos usado el siguiente comando para aplicarlo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubectl apply -f gitlab-runner.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creación de nuestro primer repo y programación de nuestra api python
&lt;/h2&gt;

&lt;p&gt;El siguiente paso ha sido crear nuestro repo de Gitlab y clonarlo(Con cuidado con la URL que te autogenera el Gitlab) usando el comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone http://URL DE NUESTRO REPO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hemos añadido dos fichero con nuestra aplicación:&lt;/p&gt;

&lt;p&gt;requirements.txt(Contiene las dependencias de nuestra aplicación Python)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fastapi&amp;gt;=0.68.0,&amp;amp;lt;0.69.0
uvicorn&amp;gt;=0.15.0,&amp;amp;lt;0.16.0 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;main.py(Contiene nuestra aplicación Python)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/")
def root():
    return {"msg": "Hello World"}

uvicorn.run(app, host="0.0.0.0", port=8080)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dockerfile para generar las imágenes Docker
&lt;/h2&gt;

&lt;p&gt;En nuestro repo también hemos creado un fichero llamado "Dockerfile" que contiene las instrucciones para generar la imagen que vamos a desplegar en Kubernetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.9

RUN mkdir /code
WORKDIR /code

ADD requirements.txt /code/requirements.txt
ADD main.py /code/main.py

RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

CMD ["python", "main.py"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Chart Helm para el despliegue
&lt;/h2&gt;

&lt;p&gt;También nos falta una carpeta llamada helm que va a contener todos los ficheros con nuestro chart para desplegar el repo:&lt;/p&gt;

&lt;p&gt;/Helm/Chart.yaml (Fichero que describe nuestro chart)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: my-super-app
version: 0.0.1
appVersion: "1.0"
description: Mi Super App 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;/helm/values.yaml(Valores o variables que configuran nuestro chart)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;appname: test1
environment: dev
namespace: test1

image: test1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;/helm/templates/deployment.yaml (Template Helm para configurar el despliegue)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ $.Values.appname }}-{{ $.Values.environment }}-deployment
  namespace: {{ $.Values.namespace }}
spec:
  selector:
    matchLabels:
      name: {{ $.Values.appname }}-{{ $.Values.environment }}-pod
  template:
    metadata:
      namespace: {{ $.Values.namespace }}
      labels:
        name: {{ $.Values.appname }}-{{ $.Values.environment }}-pod
    spec:
      containers:
      - name: pod
        image: {{ $.Values.image }}
      imagePullSecrets:
      - name: regcred
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;/helm/templates/service.yaml  (Template Helm para configurar el servicio)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: {{ $.Values.appname }}-service
  namespace: {{ $.Values.namespace }}
spec:
  type: LoadBalancer
  selector:
    name: {{ $.Values.appname }}-{{ $.Values.environment }}-pod
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configurar el Pipeline de despliegue
&lt;/h2&gt;

&lt;p&gt;Esto es quizás lo mas importante del vídeo, en Gitlab CICD, el pipeline de despliegue viene configurado en un fichero en el propio repo llamado ".gitlab-ci.yml". En nuestro caso nos hemos configurado un pipeline con cuatro stages "version", "tests", "build image" y "deploy":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variables:
  KUBERNETES_NAMESPACE: test1
  DOCKER_REGISTRY_HOST: https://index.docker.io/v1/
  DOCKER_REGISTRY_USER: acoronadoc
  DOCKER_REGISTRY_PASSWORD: dckr_pat_GegpqyANy7NViEmIDjNQATERUmM

default:
  tags:
    - kubernetes
  image: alpine:latest

stages:
  - version
  - test
  - build-image
  - deploy

version:
  stage: version
  script:
    - echo "VERSION=$(date +%Y%m%d%H%M%S%N)-$CI_COMMIT_BRANCH" &amp;gt;&amp;gt; build.env
  artifacts:
    reports:
      dotenv: build.env

test:
  stage: test
  script:
    - echo "Testing..."

buid-image:
  stage: build-image
  image: 
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script:
    - pwd
    - ls
    - mkdir -p /kaniko/.docker
    - |
      echo "{ \"auths\": { \"$DOCKER_REGISTRY_HOST\": { \"auth\": \"$(echo -n $DOCKER_REGISTRY_USER:$DOCKER_REGISTRY_PASSWORD | base64 -w0)\" } } }" &amp;gt; /kaniko/.docker/config.json
    - cat /kaniko/.docker/config.json
    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination=$DOCKER_REGISTRY_USER/$CI_PROJECT_NAME:$VERSION 

deploy:
  stage: deploy
  script:    
    - apk add kubectl helm
    - cd helm
    - kubectl create namespace $KUBERNETES_NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
    - kubectl create secret docker-registry regcred -n $KUBERNETES_NAMESPACE --docker-server=$DOCKER_REGISTRY_HOST --docker-username=$DOCKER_REGISTRY_USER --docker-password=$DOCKER_REGISTRY_PASSWORD --dry-run=client -o yaml | kubectl apply -f -
    - helm upgrade --install $CI_PROJECT_NAME . --set image=$DOCKER_REGISTRY_USER/$CI_PROJECT_NAME:$VERSION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si lo analizáis bien veréis que tenemos un script por stage, en el vídeo los he comentado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subir código y ver como se despliega
&lt;/h2&gt;

&lt;p&gt;Con todo ahora ya solo nos queda añadir todos los ficheros al repo(Cuidado porque el .gitlab-ci.yml se tiene que especificar al ser oculto), hacer el commit y hacer el push para ver los resultados:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add *
git add .gitlab-ci.yml

git commit -m "Primer commit"

git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y el resto ya es historia :D&lt;/p&gt;

</description>
      <category>devops</category>
      <category>spanish</category>
      <category>gitlab</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Tutorial de punteros en Go</title>
      <dc:creator>Albert Coronado</dc:creator>
      <pubDate>Mon, 24 Apr 2023 13:09:03 +0000</pubDate>
      <link>https://dev.to/acoronadoc/tutorial-de-punteros-en-go-hfp</link>
      <guid>https://dev.to/acoronadoc/tutorial-de-punteros-en-go-hfp</guid>
      <description>&lt;p&gt;Este artículo está basado en el vídeo de la semana pasada sobre punteros en Go, aquí lo tendréis explicado con texto y acceso al código fuente(Así no tenéis que copiar de la pantalla, que os conozco :D). Si os resulta útil podéis darle a like, compartir, comentar, etc. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/NZZ_Yrdd-2U"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducción a los punteros
&lt;/h2&gt;

&lt;p&gt;Los punteros, a diferencia de las variables donde el compilador reserva una posición de memoria para almacenar información, estos no tienen una posición de memoria reservada y pueden apuntar a la posición de memoria que les indiquemos.&lt;/p&gt;

&lt;p&gt;Por ejemplo, en el siguiente ejemplo declaramos una variable llamada 'v' con el valor '4', seguidamente imprimimos por pantalla el valor de la variable y su posición de memoria(Con el símbolo '&amp;amp;' accedemos a la posición de memoria de una variable). Después, tenemos declarado el puntero 'p' al que apuntamos a la posición de memoria de la variable 'v' y le asignamos otro valor(Con el símbolo '*' accedemos al valor de la posición de memoria de un puntero).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var v int = 4
var p *int

fmt.Printf( "El valor de v es %d \n", v )
fmt.Printf( "La posición de memória de v es %v \n", &amp;amp;v )

p = &amp;amp;v
*p = 8

fmt.Printf( "El valor de p es %d \n", *p )
fmt.Printf( "La posición de memória de p es %v \n", p )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso de parámetros por valor o referencia
&lt;/h2&gt;

&lt;p&gt;Una de las aplicaciones del uso de punteros es pasar variables a las funciones por referencia. Cuando pasamos un parámetro a una función por 'valor' el compilador lo que hace es reservar una posición de memoria para ese parámetro y copiarle el valor. Si lo hacemos por 'referencia', es decir, usando punteros estamos usando la misma posición de memoria y, por lo tanto, es mucho más rápido.&lt;/p&gt;

&lt;p&gt;Hemos hecho un ejemplo de esto en el vídeo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

func main() {
    var v int = 4
    var p *int

    p = &amp;amp;v
    *p = 8

    IncValor( v )
    IncReferencia( &amp;amp;v )

    fmt.Printf( "El valor de v es %d \n", v )
    fmt.Printf( "La posición de memória de v es %v \n", &amp;amp;v )

        fmt.Printf( "El valor de p es %d \n", *p )
        fmt.Printf( "La posición de memória de p es %v \n", p )
}

func IncValor( v int  ) {
    v++
    fmt.Printf( "El valor incrementado(Por valor) es %d \n", v )
    }

func IncReferencia( v *int ) {
    *v++
    fmt.Printf( "El valor incrementado(Por referencia) es %d \n", *v )
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Listas con punteros
&lt;/h2&gt;

&lt;p&gt;Otra aplicación de los punteros donde se demuestra su potencia es creando estructuras de datos. En el vídeo hemos creado un CRUD(Create-Read-Update-Delete) de clientes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import "fmt"

type Cliente struct {
    nombre string
    telefono string
    next *Cliente
}

var primerCliente *Cliente

func main() {
    AddCliente( "Pepe", "555 555 555" )
        AddCliente( "Juan", "555 555 556" )
        AddCliente( "Rodrigo", "555 555 557" )
        AddCliente( "David", "555 555 558" )

    ListaClientes()

    var cliente *Cliente = GetCliente(2)
    (*cliente).nombre = "Albert"

    fmt.Printf( "\nClientes Update\n" )
    ListaClientes()

    DeleteCliente( 2 )
    fmt.Printf( "\nClientes Delete\n" )
        ListaClientes()
    }

func AddCliente(nombre string, telefono string) {
    var cliente = Cliente{
        nombre:   nombre,
        telefono: telefono,
        next:     nil,
    }

    if primerCliente == nil {
        primerCliente = &amp;amp;cliente

        return
    }

    var nextCliente *Cliente = primerCliente
    for nextCliente.next != nil {
        nextCliente = nextCliente.next
    }

    nextCliente.next = &amp;amp;cliente
}

func ListaClientes() {
    if primerCliente == nil {
        return
    }

    var nextCliente *Cliente = primerCliente
    for nextCliente.next != nil {
        fmt.Printf("Nombre: %s Teléfono: %s \n", nextCliente.nombre, nextCliente.telefono)

        nextCliente = nextCliente.next
    }

    fmt.Printf("Nombre: %s Teléfono: %s \n", nextCliente.nombre, nextCliente.telefono)
}

func GetCliente(pos int) *Cliente {
    if primerCliente == nil {
        return nil
    }

    var nextCliente *Cliente = primerCliente
    i := 0
    for i &amp;lt; pos &amp;amp;&amp;amp; nextCliente.next != nil {
        nextCliente = nextCliente.next
        i++
    }

    if i != pos {
        return nil
    }

    return nextCliente
}

func DeleteCliente(pos int) {
    if primerCliente == nil {
        return
    }

    if pos == 0 {
        if primerCliente.next == nil {
            primerCliente = nil

            return
        }

        primerCliente = primerCliente.next
        return
    }

    var cliente *Cliente = GetCliente(pos)
    var previo *Cliente = GetCliente(pos - 1)
    if cliente == nil || previo == nil {
        return
    }

    previo.next = cliente.next
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el ejemplo, hemos creado una estructura para almacenar clientes donde también tenemos un puntero al siguiente cliente. De esta manera podemos recorrer los clientes desde el primero hasta que encontremos el último(El que el puntero 'next' tiene valor None) y para eliminar uno de la lista simplemente hay que quitarlo de la cadena(En el caso de Go, a diferencia de C, no hace falta liberar la memoria porque lo hace solo con el recolector de basura).&lt;/p&gt;

&lt;p&gt;Podemos optimizar el ejemplo para distintos casos de uso: Con dos punteros(Uno para next y otro para prev y así recorrer la lista en dos direcciones), con otro puntero que apunte al final de la lista, con otro puntero en la mitad de la lista, con punteros para ordenar los registros usando un índice, etc.&lt;/p&gt;

&lt;p&gt;En fin, espero que hayáis disfrutado del contenido y os haya resultado útil. La mejor manera de colaborar es dándole a like, comentar y compartir, a ver si hacemos que esta red social se llene de contenido hispano hablante... &lt;/p&gt;

</description>
      <category>spanish</category>
      <category>tutorial</category>
      <category>go</category>
    </item>
    <item>
      <title>Python Crash Course, de 0 a 100 con Python</title>
      <dc:creator>Albert Coronado</dc:creator>
      <pubDate>Tue, 11 Apr 2023 13:50:35 +0000</pubDate>
      <link>https://dev.to/acoronadoc/python-crash-course-de-0-a-100-con-python-59in</link>
      <guid>https://dev.to/acoronadoc/python-crash-course-de-0-a-100-con-python-59in</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/siQvDvRPbS4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Hoy os dejo todo el código del videotutorial de Python en esta comunidad. Así que si me queréis seguir, comentar, darle a like, etc. me haréis un favor(Tanto aquí como en Youtube, Linkedin, etc.)(Sí, soy mu pesao).&lt;/p&gt;

&lt;h2&gt;
  
  
  Estructuras de datos
&lt;/h2&gt;

&lt;p&gt;Lo primero que hemos hecho ha sido trabajar con variables y estructuras de datos. Python tiene los típicos tipos básicos Integer, Float, Boolean y Strings pero donde realmente destaca es por su soporte nativo a listas, tuplas y diccionarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mylist = [ "java", "go", "php", "python", "nodejs" ]

print( "" )
print( "Listas" )
print( "===============================================================" )
print( "mylist: %s" % mylist )
print( "Intervalo 1 a 4: %s" % mylist[1:4] )
print( "Intervalo 1 al final: %s" % mylist[1:] )
print( "Intervalo posición 2 empezando por atrás al final: %s" % mylist[-2:] )

mylist.append( "rust" )
mylist.remove( "php" )
mylist.append( 4 )

print( "Añado 'rust', quito 'php', añado 4: %s" %mylist )

# Las tuplas son como las listas pero inmutables. Su principal ventaja es el poco espacio que ocupan en memória

mytupla = ( "java", "go", "php", "python", "nodejs" )

print( "" )
print( "Tuplas" )
print( "===============================================================" )
print( "mytupla: {0}".format(mytupla) )

# Diccionarios

print( "" )
print( "Diccionarios" )
print( "===============================================================" )
mydict = { "hello": "world", "mylist": mylist, "mytupla": mytupla }

print( "mydict: {0}".format(mydict) )
print( "Valor de 'hello': {0}({1})".format(mydict['hello'], type(mydict['hello'])) )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Estructuras de control: condicionales y bucles
&lt;/h2&gt;

&lt;p&gt;Después de ver las estructuras de datos hemos visto como crear condicionales y bucles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# bucles
print( "" )
print( "Bucles" )
print( "===============================================================" )

for x in mydict:
    print( "keys: {0}".format(x) )

for x, y in mydict.items():
    print( "{0} = {1}".format(x, y) )    

for x in mydict.values():
    print( "values: {0}".format(x) )    

for x in range(1,5):
    print( "Rango: {0}".format(x) )    

count = 0
while count &amp;lt; 5:
    print( "Condición: {0}".format(count) )
    count += 1

# condicionales
print( "" )
print( "Condicionales" )
print( "===============================================================" )

for x in mytupla:
    print( "Procesando: {0}".format(x) )

    if x == "go":
        print( " Es Go!!!!!!!!!!!!!!!!!!!!!!!!!" )
    else:
        print( " No es go" )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Estructuración del código: Funciones, lambdas y classes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Funciones y lambdas
def my_function( myparam ):
    print( "El parámetro de mi función es: {0}".format( myparam ) )

    return "ok"

print( "" )
print( "funciones" )
print( "===============================================================" )
my_function( mylist )

print( "" )
print( "lambdas" )
print( "===============================================================" )
mylamda = lambda x,y:x+y
print( "El resultado de 2+5={0}".format( mylamda(2,5) ) )

# Classes
print( "" )
print( "Condicionales" )
print( "===============================================================" )

class Vehiculo:
    def __init__(self, ruedas):
        self.ruedas = ruedas

coche = Vehiculo( 4 )
print( coche )
print( vars(coche) )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Módulos
&lt;/h2&gt;

&lt;p&gt;Los módulos nos permiten organizar el código y para ilustrar su funcionamiento hemos creado un fichero llamado 'mymodule.py' con una variable y una función:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mymodulevar = { "customer_id":12, "total": 15000 }

def mymodulefunc():
    print( "Module func" )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Después hemos creado un segundo fichero en python y hemos hecho uso de sus recursos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import mymodule

mymodule.mymodulefunc()

x = dir(mymodule)

print(x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus Track: Script Ejecutable
&lt;/h2&gt;

&lt;p&gt;Finalmente, hemos visto como podíamos crear un script ejecutable con python simplemente creando un archivo y añadiendo en su cabecera &lt;code&gt;#!/usr/bin/env python3&lt;/code&gt; y dándole permisos de ejecución con &lt;code&gt;chmod +x myfichero&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;También hemos usado el módulo 'argparse' que nos ofrece el API de Python para parsear argumentos. El código del script es el siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env python3
import argparse

parser = argparse.ArgumentParser(description="PaaS deployment tool.", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-r', '--repository', required=True, help="Gitlab repository URL.") 
parser.add_argument('-e', '--environment', choices=["dev","pre", "pro"], default="dev", required=False, help="Environment.") 
parser.add_argument('action', nargs="?", choices=["deploy"], default="deploy", help="Openshift project name.") 

args = vars( parser.parse_args() )

print( "" )
print( "Argumentos:" )
print( "  %s" % args )
print( "" )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¡Esto es todo amigos! Espero que lo disfrutéis.&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Older versions of Docker over Docker Machine</title>
      <dc:creator>Albert Coronado</dc:creator>
      <pubDate>Mon, 20 Dec 2021 10:46:58 +0000</pubDate>
      <link>https://dev.to/acoronadoc/older-versions-of-docker-over-docker-machine-1dni</link>
      <guid>https://dev.to/acoronadoc/older-versions-of-docker-over-docker-machine-1dni</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp2sbmxersezqhrap75y6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp2sbmxersezqhrap75y6.png" alt="Docker logo" width="560" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sometimes we may need use different versions of Docker on our machine. We may interest this functionality in order to support older versions of Docker on our developments. In my case, I needed an older version of Docker because new versions of Docker require ‘Content-Length’ header to download images from a repository(The rest is another history).&lt;/p&gt;

&lt;p&gt;We may deploy any versions of Docker using Docker Machine just adding the '--virtualbox-boot2docker-url' parameter:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-machine create -d virtualbox --virtualbox-boot2docker-url https://github.com/boot2docker/boot2docker/releases/download/v18.09.8/boot2docker.iso ics2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I hope help anyone with this tip. &lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
